【问题标题】:Save WebAPI response as PDF file将 WebAPI 响应保存为 PDF 文件
【发布时间】:2019-07-26 09:07:43
【问题描述】:

我编写了返回文件的 WebAPI GET 方法,我检查了 SoapUI 的工作情况。现在我想调用该服务并将文件作为 PDF 保存在本地驱动器中,我正在从服务中获得响应,但是如何将响应转换为 PDF 格式的文件?

public async Task<IActionResult> FileIndex()
{
    try
    {
        HttpClientHandler clientHandler = new HttpClientHandler();

        clientHandler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => { return true; };

        HttpClient client = new HttpClient(clientHandler);
        HttpResponseMessage response = await client.GetAsync("https://test-server/api/files");

        if (response.IsSuccessStatusCode)
        {
            var output= await response.Content.ReadAsAsync<byte[]>();
            System.IO.File.WriteAllBytes(@"E:\testpdf.pdf", output);
        }
    }
    catch (Exception ex)
    {
    }

    return View();
}

var output... 上抛出异常

读取字节时出错。意外标记:StartObject。路径“版本”, 第 1 行,位置 11

SoapUI 中的响应

{
   "version":    {
      "major": 1,
      "minor": 1,
      "build": -1,
      "revision": -1,
      "majorRevision": -1,
      "minorRevision": -1
   },
   "content": {"headers":    [
            {
         "key": "Content-Disposition",
         "value": ["attachment; filename=\"About Us.pdf\""]
      },
            {
         "key": "Content-Type",
         "value": ["application/octet-stream"]
      }
   ]},
   "statusCode": 200,
   "reasonPhrase": "OK",
   "headers": [],
   "requestMessage": null,
   "isSuccessStatusCode": true
}

【问题讨论】:

  • 那么当你运行上面的代码时出了什么问题呢? API 的响应实际上是否已经包含 PDF 格式的数据,或者它是否返回其他内容,并且您想基于该数据创建 PDF 文档?有点不清楚
  • Web API 响应的Content-Type 是什么?如果不是application/pdf,那么您实际上并没有在响应中收到 PDF 文档。
  • 在``` var output```上抛出异常“读取字节时出错。意外的标记:StartObject。路径'版本',第1行,位置11。”。添加响应
  • 这看起来像是 SOAPUI 读取 HTTP 标头并以 JSON 格式显示给您?还是那是实际的响应体??
  • P.S. catch (Exception ex) { }anti-pattern。它会阻止您查看代码是否有错误。如果您要捕获异常,您至少必须在某处记录异常详细信息,以便您可以看到正在发生的错误,并能够使用这些信息来诊断原因。

标签: c# http pdf asp.net-core asp.net-core-webapi


【解决方案1】:

我认为您的主要问题是尝试在您的 FileIndex() 方法中使用来自 Microsoft.AspNet.WebApi.ClientReadAsAsync&lt;byte[]&gt;

var output = await response.Content.ReadAsAsync<byte[]>();

这适用于 JSON 响应。有一些链接错误地声称您可以通过将 a 行添加到您的 WebApiConfig.cs 来使其与 application/octet-stream 响应一起使用,例如:

config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/octet-stream"));

我认为这个建议是有缺陷的,我一直无法让它发挥作用。如果您的项目中有该行,则应将其删除并在您的 FileIndex() 方法中使用以下内容:

var output = await response.Content.ReadAsByteArrayAsync();

这是一个完整的控制台应用程序,它使用来自 Web API 方法的 application/pdf 流并将其保存到磁盘(在 TestClient.exe 文件旁边的 TestClient/bin/Debug 文件夹中):

using System.Net.Http;
using System.Threading.Tasks;

namespace TestClient
{
    class MainClass
    {
        public static async Task FileIndex()
        {
            HttpClientHandler clientHandler = new HttpClientHandler();

            var requestUri = "http://localhost:8080/api/files";

            //var requestUri = "https://test-server/api/files";
            //clientHandler.ServerCertificateCustomValidationCallback =
            //    (sender, cert, chain, sslPolicyErrors) => { return true; };

            HttpClient client = new HttpClient(clientHandler);
            HttpResponseMessage response = await client.GetAsync(requestUri);

            if (response.IsSuccessStatusCode)
            {
                var output = await response.Content.ReadAsByteArrayAsync();
                //var path = @"E:\testpdf.pdf";
                var path = @"testpdf.pdf";
                System.IO.File.WriteAllBytes(path, output);
            }
        }

        public static void Main(string[] args)
        {
            FileIndex().Wait();
        }
    }
}

这是我实现的一个控制器,它演示了如何使用正确的 MIME 类型和其他元数据信息将 PDF 文件返回给客户端:

using System;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Web;
using System.Web.Mvc;

namespace TestServer.Controllers
{
    public class FilesController : System.Web.Http.ApiController
    {
        [Authorize]
        [HttpGet]
        public HttpResponseMessage Get()
        {
            try
            {
                var fileName = "testpdf.pdf";

                // Where "~/" is the root folder of the Web API server project...
                var localFilePath = HttpContext.Current.Server.MapPath("~/" + fileName);

                var fileInfo = new FileInfo(localFilePath);
                var result = new HttpResponseMessage(HttpStatusCode.OK);

                // WARNING: Don't use IDisposables or using(){} blocks here.
                // IDisposables would need to exist for the duration of the client download.
                result.Content = new ByteArrayContent(File.ReadAllBytes(localFilePath));

                result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
                result.Content.Headers.ContentDisposition.FileName = fileName;
                result.Content.Headers.ContentDisposition.CreationDate = fileInfo.CreationTimeUtc;
                result.Content.Headers.ContentDisposition.ModificationDate = fileInfo.LastWriteTimeUtc;
                result.Content.Headers.ContentDisposition.ReadDate = fileInfo.LastAccessTimeUtc;
                result.Content.Headers.ContentLength = fileInfo.Length;
                result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
                return result;
            }
            catch (Exception ex)
            {
                //Use something proper like Serilog to log the exception here...
                Console.WriteLine(ex.ToString(), ex.Message);
            }
            return new HttpResponseMessage(HttpStatusCode.Gone);
        }
    }
}

希望这会有所帮助!

【讨论】:

  • 感谢此代码正在运行,但是当文件保存到磁盘时,它显示已损坏,无法打开..
【解决方案2】:

您可以使用此示例来说明您的需求。

public void GeneratePdf(string htmlPdf)
{
   var pdfDoc = new Document(PageSize.A4, 10f, 10f, 10f, 0f);
   var htmlparser = new HTMLWorker(pdfDoc);
   using (var memoryStream = new MemoryStream())
   {
       var writer = PdfWriter.GetInstance(pdfDoc, memoryStream);
       pdfDoc.Open();

       htmlparser.Parse(new StringReader(htmlPdf));
       pdfDoc.Close();

       byte[] bytes = memoryStream.ToArray();
       File.WriteAllBytes(@"C:\file.pdf", bytes);

       memoryStream.Close();
}

}

【讨论】:

  • 您写了“我如何将响应转换为 PDF 格式的文件”。你很奇怪
  • 1) 我没有问这个问题 - 更仔细地查看用户名! 2)这个答案不涉及下载 PDF 文档并将其保存到磁盘。您在这里所做的是创建一个空白 PDF 文档并在其中插入一些 HTML。您是从哪里得知涉及 HTML 的?并非从网络服务器下载的所有内容都是 HTML。这个问题非常明确,GET 请求应该下载 PDF 数据,而当尝试读取该数据并将其存储在磁盘上时,问题就出现了。这就是为什么你的回答与问题无关。
  • @ADyson 为了公平对待弗拉基米尔,这是一个质量很差的问题。它确实问,关键字是 convert 而不是 save “我正在从服务中获得响应,但是我如何将响应 convert 响应到文件中PDF 格式?”
  • @AlwaysLearning 确实如此,但查看实际代码以及显示“保存”的问题标题很快就能清楚真正的意图是什么。
猜你喜欢
  • 1970-01-01
  • 2016-08-21
  • 2021-11-24
  • 2014-04-15
  • 1970-01-01
  • 1970-01-01
  • 2012-09-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多