programing

웹 API 응용 프로그램에서 PDF를 반환하는 방법

topblog 2023. 8. 26. 10:15
반응형

웹 API 응용 프로그램에서 PDF를 반환하는 방법

서버에서 실행 중인 웹 API 프로젝트가 있습니다.실제 휴대용 문서 파일(PDF)과 데이터베이스에 저장된 base64 문자열 등 두 가지 종류의 소스에서 PDF를 반환해야 합니다.문제는 고객 MVC 애플리케이션으로 문서를 다시 보내는 것입니다.나머지는 제가 이미 시도한 모든 일에 대한 세부사항입니다.

저는 이 두 가지 형식을 C# 코드로 성공적으로 변환한 다음 PDF 형식으로 변환하는 코드를 작성했습니다.해당 문서 중 하나를 나타내는 바이트 배열을 성공적으로 전송했지만 브라우저에 표시할 수 없습니다(새 탭에서만).항상 "표시할 수 없음" 오류가 발생합니다.

최근에, 저는 최소한 그렇게 할 수 있도록 서버 쪽의 문서를 볼 수 있는 방법을 만들었습니다.문서를 코드로 가져온 다음 FileStreamResult를 생성하여 (암묵적으로 캐스트된) 작업 결과로 반환합니다.저는 서버 측 MVC 컨트롤러로 돌아가기 위해 그것을 가져왔고 브라우저에 PDF가 잘 표시되는 간단한 반환(보기 없음)에 던졌습니다.그러나 웹 API 함수로 바로 이동하려고 하면 FileStreamResult의 JSON 표현처럼 보이는 것만 반환됩니다.

클라이언트 MVC 응용 프로그램으로 올바르게 되돌리려고 하면 "_buffer"를 직접 설정할 수 없다는 메시지가 나타납니다.반환되어 개체에 던져지는 일부 속성이 비공개이므로 액세스할 수 없다는 취지의 일부 오류 메시지입니다.

위에서 언급한 PDF의 바이트 배열 표현은 base64 문자열로 변환될 때 FileStreamResult에 의해 JSON에서 반환된 "_buffer" 문자열과 동일한 수의 문자를 가지고 있지 않은 것 같습니다.마지막에 약 26k 'A'가 누락되었습니다.

이 PDF를 올바르게 반환하는 방법에 대한 아이디어가 있습니까?필요한 경우 코드를 제공할 수 있지만 서버 측 웹 API 응용 프로그램에서 클라이언트 측 MVC 응용 프로그램으로 PDF를 반환하고 브라우저에 웹 페이지로 표시할 수 있는 알려진 방법이 있어야 합니다.

추신: "클라이언트 측" 애플리케이션이 기술적으로 클라이언트 측에 있지 않다는 것은 알고 있습니다.서버 응용프로그램이기도 하지만 이 경우에는 문제가 되지 않습니다.웹 API 서버와 관련하여, 내 MVC 애플리케이션은 "클라이언트 측"입니다.

PDF를 가져오는 코드:

private System.Web.Mvc.ActionResult GetPDF()
{
    int bufferSize = 100;
    int startIndex = 0;
    long retval;
    byte[] buffer = new byte[bufferSize];
    MemoryStream stream = new MemoryStream();
    SqlCommand command;
    SqlConnection sqlca;
    SqlDataReader reader;

    using (sqlca = new SqlConnection(CONNECTION_STRING))
    {
        command = new SqlCommand((LINQ_TO_GET_FILE).ToString(), sqlca);
        sqlca.Open();
        reader = command.ExecuteReader(CommandBehavior.SequentialAccess);
        try
        {
            while (reader.Read())
            {
                do
                {
                    retval = reader.GetBytes(0, startIndex, buffer, 0, bufferSize);
                    stream.Write(buffer, 0, bufferSize);
                    startIndex += bufferSize;
                } while (retval == bufferSize);
            }
        }
        finally
        {
            reader.Close();
            sqlca.Close();
        }
    }
    stream.Position = 0;
    System.Web.Mvc.FileStreamResult fsr = new System.Web.Mvc.FileStreamResult(stream, "application/pdf");
    return fsr;
}

GetPDF에서 제공하는 API 함수:

    [AcceptVerbs("GET","POST")]
    public System.Web.Mvc.ActionResult getPdf()
    {
        System.Web.Mvc.ActionResult retVal = GetPDF();
        return retVal;
    }

PDF 서버 측을 표시하는 경우:

public ActionResult getChart()
{
    return new PDFController().GetPDF();
}

MVC 애플리케이션의 코드는 시간이 지남에 따라 많이 변경되었습니다.현재 상태로는 브라우저에 표시하려는 단계에 도달하지 않습니다.그 전에 오류가 발생합니다.

public async Task<ActionResult> get_pdf(args,keys)
{
    JObject jObj;
    StringBuilder argumentsSB = new StringBuilder();
    if (args.Length != 0)
    {
        argumentsSB.Append("?");
        argumentsSB.Append(keys[0]);
        argumentsSB.Append("=");
        argumentsSB.Append(args[0]);
        for (int i = 1; i < args.Length; i += 1)
        {
            argumentsSB.Append("&");
            argumentsSB.Append(keys[i]);
            argumentsSB.Append("=");
            argumentsSB.Append(args[i]);
        }
    }
    else
    {
        argumentsSB.Append("");
    }
    var arguments = argumentsSB.ToString();
    using (var client = new HttpClient())
    {
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        var response = await client.GetAsync(URL_OF_SERVER+"api/pdf/getPdf/" + arguments).ConfigureAwait(false);
        jObj = (JObject)JsonConvert.DeserializeObject(response.Content.ReadAsStringAsync().Result);
    }
    return jObj.ToObject<ActionResult>();
}

웹 API 컨트롤러에서 메소드를 직접 실행하여 얻는 JSON은 다음과 같습니다.

{
    "FileStream":{
        "_buffer":"JVBER...NjdENEUxAA...AA==",
        "_origin":0,
        "_position":0,
        "_length":45600,
        "_capacity":65536,
        "_expandable":true,
        "_writable":true,
        "_exposable":true,
        "_isOpen":true,
        "__identity":null},
    "ContentType":"application/pdf",
    "FileDownloadName":""
}

"_buffer"가 터무니없이 길기 때문에 단축했습니다.현재 get_pdf(args, key)의 반환 줄에 아래 오류 메시지가 표시됩니다.

예외 세부 정보:뉴턴소프트.Json.Json 직렬화예외:시스템 유형의 인스턴스를 만들 수 없습니다.웹.MVC.작업 결과.유형은 인터페이스 또는 추상 클래스이므로 인스턴스화할 수 없습니다.경로 'FileStream'입니다.

제가 빈 pdf 리더(독자가 빈 pdf 리더)를 얻곤 했던 시절.파일 없음), 다음 코드를 사용했습니다.

public async Task<ActionResult> get_pdf(args,keys)
{
    byte[] retArr;
    StringBuilder argumentsSB = new StringBuilder();
    if (args.Length != 0)
    {
        argumentsSB.Append("?");
        argumentsSB.Append(keys[0]);
        argumentsSB.Append("=");
        argumentsSB.Append(args[0]);
        for (int i = 1; i < args.Length; i += 1)
        {
            argumentsSB.Append("&");
            argumentsSB.Append(keys[i]);
            argumentsSB.Append("=");
            argumentsSB.Append(args[i]);
        }
    }
    else
    {
        argumentsSB.Append("");
    }
    var arguments = argumentsSB.ToString();
    using (var client = new HttpClient())
    {
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/pdf"));
        var response = await client.GetAsync(URL_OF_SERVER+"api/webservice/" + method + "/" + arguments).ConfigureAwait(false);
        retArr = await response.Content.ReadAsByteArrayAsync().ConfigureAwait(false);
    }
    var x = retArr.Skip(1).Take(y.Length-2).ToArray();
    /*Response.Clear();
    Response.ClearContent();
    Response.ClearHeaders();
    Response.ContentType = "application/pdf";
    Response.AppendHeader("Content-Disposition", "inline;filename=document.pdf");
    Response.BufferOutput = true;
    Response.BinaryWrite(x);
    Response.Flush();
    Response.End();*/
    return new FileStreamResult(new MemoryStream(x),MediaTypeNames.Application.Pdf);
    }

주석 처리된 코드는 다른 시도의 코드입니다.그 코드를 사용할 때 서버에서 바이트 배열을 반환하고 있었습니다.그것은 다음과 같이 보였습니다.

JVBER...NjdENEUx

PDF(Web API)를 반환할 일부 서버 사이드 코드입니다.

[HttpGet]
[Route("documents/{docid}")]
public HttpResponseMessage Display(string docid) {
    HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.BadRequest);
    var documents = reader.GetDocument(docid);
    if (documents != null && documents.Length == 1) {
        var document = documents[0];
        docid = document.docid;
        byte[] buffer = new byte[0];
        //generate pdf document
        MemoryStream memoryStream = new MemoryStream();
        MyPDFGenerator.New().PrintToStream(document, memoryStream);
        //get buffer
        buffer = memoryStream.ToArray();
        //content length for use in header
        var contentLength = buffer.Length;
        //200
        //successful
        var statuscode = HttpStatusCode.OK;
        response = Request.CreateResponse(statuscode);
        response.Content = new StreamContent(new MemoryStream(buffer));
        response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
        response.Content.Headers.ContentLength = contentLength;
        ContentDispositionHeaderValue contentDisposition = null;
        if (ContentDispositionHeaderValue.TryParse("inline; filename=" + document.Name + ".pdf", out contentDisposition)) {
            response.Content.Headers.ContentDisposition = contentDisposition;
        }
    } else {
        var statuscode = HttpStatusCode.NotFound;
        var message = String.Format("Unable to find resource. Resource \"{0}\" may not exist.", docid);
        var responseData = responseDataFactory.CreateWithOnlyMetadata(statuscode, message);
        response = Request.CreateResponse((HttpStatusCode)responseData.meta.code, responseData);
    }
    return response;
}

내 관점에서 당신은 다음과 같은 것을 할 수 있습니다.

<a href="api/documents/1234" target = "_blank" class = "btn btn-success" >View document</a>

웹 API를 호출하고 브라우저의 새 탭에서 PDF 문서를 엽니다.

MVC 컨트롤러를 제외하고 기본적으로 동일한 작업을 수행하는 방법은 다음과 같습니다.

// NOTE: Original return type: FileContentResult, Changed to ActionResult to allow for error results
[Route("{docid}/Label")]
public ActionResult Label(Guid docid) {
    var timestamp = DateTime.Now;
    var shipment = objectFactory.Create<Document>();
    if (docid!= Guid.Empty) {
        var documents = reader.GetDocuments(docid);
        if (documents.Length > 0)
            document = documents[0];

            MemoryStream memoryStream = new MemoryStream();
            var printer = MyPDFGenerator.New();
            printer.PrintToStream(document, memoryStream);

            Response.AppendHeader("Content-Disposition", "inline; filename=" + timestamp.ToString("yyyyMMddHHmmss") + ".pdf");
            return File(memoryStream.ToArray(), "application/pdf");
        } else {
            return this.RedirectToAction(c => c.Details(id));
        }
    }
    return this.RedirectToAction(c => c.Index(null, null));
}

이것이 도움이 되길 바랍니다.

에서 pdf 파일을 반환해야 했습니다.NET core 3.1 web api에서 다음과 같은 훌륭한 기사를 발견했습니다.

https://codeburst.io/download-files-using-web-api-ae1d1025f0a9

기본적으로 다음과 같이 전화합니다.

var bytes = await System.IO.File.ReadAllBytesAsync(pathFileName);
return File(bytes, "application/pdf", Path.GetFileName(pathFileName));

전체 코드:

using Microsoft.AspNetCore.Mvc;
using System.IO;

using Reportman.Drawing;
using Reportman.Reporting;
using System.Text;
using System.Threading.Tasks;

[Route("api/[controller]")]
[ApiController]
public class PdfController : ControllerBase
{
    [HttpGet]
    [Route("ot/{idOT}")]
    public async Task<ActionResult> OT(string idOT)
    {
        Report rp = new Report();
        rp.LoadFromFile("ot-net.rep"); // File created with Reportman designer
        rp.ConvertToDotNet();

        // FixReport
        rp.AsyncExecution = false;
        PrintOutPDF printpdf = new PrintOutPDF();

        // Perform the conversion from one encoding to the other.
        byte[] unicodeBytes = Encoding.Convert(Encoding.ASCII, Encoding.Unicode, Encoding.ASCII.GetBytes($"Orden de trabajo {idOT}"));
        string unicodeString = new string(Encoding.Unicode.GetChars(unicodeBytes));
        // todo: convert to unicode
        // e = Encoding.GetEncoding(unicodeString);
        // System.Diagnostics.Trace.WriteLine(e);
        if (rp.Params.Count > 0)
        {
            rp.Params[0].Value = unicodeString;
        }

        printpdf.FileName = $"ot-{idOT}.pdf";
        printpdf.Compressed = false;

        if (printpdf.Print(rp.MetaFile))
        {
            // Download Files using Web API. Changhui Xu. https://codeburst.io/download-files-using-web-api-ae1d1025f0a9
            var bytes = await System.IO.File.ReadAllBytesAsync(printpdf.FileName);
            return File(bytes, "application/pdf", Path.GetFileName(printpdf.FileName));
        }

        return null;
    }

이 API에 대한 호출은 다음과 같습니다. https://localhost:44387/api/pdf/ot/7

Reportman은 다음 사이트에서 찾을 수 있는 PDF 생성기입니다. https://reportman.sourceforge.io/

맛있게 드세요!

언급URL : https://stackoverflow.com/questions/36042614/how-to-return-a-pdf-from-a-web-api-application

반응형