【问题标题】:Download PDF File from API Using C#使用 C# 从 API 下载 PDF 文件
【发布时间】:2016-06-13 21:27:36
【问题描述】:

我正在创建一个控制台应用程序,

  1. 连接到供应商 API 以提取两个日期之间提交费用的凭证编号,并且
  2. 下载随费用提交的收据的 PDF 副本

第一部分,我工作得很好。我可以使用以下代码连接到供应商 API 并解析返回的 XML 以创建凭证编号数组(需要获取 PDF 图像):

static async Task RunAsyncCR()
        {
            using (var client = new HttpClient())
            {
                var values = new Dictionary<string, string>
                {
                    {"un","SomeUser"},
                    {"pw","SomePassword"},
                    {"method","getVoucherInvoices"},
                    {"fromDate","05/30/2016"},
                    {"toDate", "06/13/2016"}
                };

                var content = new FormUrlEncodedContent(values);

                Console.WriteLine("Connecting...");

                var response = await client.PostAsync("https://www.chromeriver.com/receipts/doit", content);

                Console.WriteLine("Connected...");

                var responseString = await response.Content.ReadAsStringAsync();

                char[] DelimiterChars = {'<'};

                String[] xmlReturn = responseString.Split(DelimiterChars);

                string[] VoucherNumber = new string[500];

                int i = 0;

                foreach (string s in xmlReturn)
                {
                    if (s.Contains("voucherInvoice>") && s != "/voucherInvoice>\n    ")
                    {
                        VoucherNumber[i] = s.Substring(15, 16);

                        i++;
                    }
                }

                Array.Resize(ref VoucherNumber, i);

是的,可能有更好的方法来做到这一点,但它可以工作并返回我期望的值。

现在,我遇到的问题是,当我连接回 API 以检索文件时,我似乎无法将文件下载到指定的文件路径。

我可以使用

连接回 API
            i = 0;

            foreach (string x in VoucherNumber)
            {
                Console.WriteLine("Get receipt: " + x);

                var NewValues = new Dictionary<string, string>
                {
                    {"un","SomeUser"},
                    {"pw","SomePassword"},
                    {"method","getReceiptsWithCoverPage"},
                    {"voucherInvoiceForPdf", VoucherNumber[i]}
                };

                var NewContent = new FormUrlEncodedContent(NewValues);

                var NewResponse = await client.PostAsync("https://www.chromeriver.com/receipts/doit", NewContent);

                string NewResponseString = await NewResponse.Content.ReadAsStringAsync();

但我似乎无法将响应写入有效文件 (PDF)

这是我逐步执行代码时的 Autos 窗口的屏幕截图,我需要在其中下载文件:

我的问题是,从现在开始,我该如何将文件保存到我的系统中?

我尝试获取从执行Console.WriteLine(NewResponseString); 得到的编码响应,并使用System.IO.File.WriteAllLines() 方法,使用指定的文件路径/名称将其写入文件,但这会导致一个空白文件。我也花了一些时间研究 Google/Stackoverflow 的深度,但不明白如何实现我找到的结果。

我们将不胜感激。

【问题讨论】:

  • 您能在此处以十六进制粘贴该流的前 20 个字节吗?
  • 您有使用 Streams 的经验吗?如果不是那是你应该开始的地方。如果这不是您的问题,也许您可​​以澄清一下 - 您需要帮助将流保存到磁盘还是需要帮助从响应中提取流/字节数组?
  • @Igor - 我没有使用流的经验 - 这是我第一次需要连接到 API 来检索文件...

标签: c# .net asp.net-web-api


【解决方案1】:

所以我认为您需要有关 Streams 的帮助。返回的HttpContent 实际上是一个System.Net.Http.StreamContent 实例,它表明您正在获取内容。它只是从该实例获取流(内容)并将其保存到文件的问题。

var NewResponse = await client.PostAsync("https://www.chromeriver.com/receipts/doit", NewContent);

System.Net.Http.HttpContent content = NewResponse.Content; // actually a System.Net.Http.StreamContent instance but you do not need to cast as the actual type does not matter in this case

using(var file = System.IO.File.Create("somePathHere.pdf")){ // create a new file to write to
    var contentStream = await content.ReadAsStreamAsync(); // get the actual content stream
    await contentStream.CopyToAsync(file); // copy that stream to the file stream
}

我恭敬地建议您阅读一下 Streams 的工作原理。这是许多语言中的常见结构,您可能在不久的将来必须再次处理。

【讨论】:

  • 谢谢,这对我有用。只要时间允许,我会做一点阅读(要做的太多,时间太少)。
  • @Igor,你为什么要做Flush操作?是不是多余的?
【解决方案2】:

首先,您确定有一个文件开头吗?我可以建议使用开源库 PdfSharp。我个人自己使用它,效果很好。至于下载文件,也许这可以帮助你......

同步下载

using System.Net;
WebClient webClient = new WebClient();
webClient.DownloadFile("http://example.com/myfile.txt", @"c:\\myfile.txt");

http://www.csharp-examples.net/download-files/

【讨论】:

  • 是的,那里肯定有一个文件,如果你看我的屏幕截图,它包含文件信息,包括返回的文件的名称。
  • 如果你想走PdfSharp路线,这里是下载链接。下面是我的一个关于如何实现pdf编写的示例。pdfsharp.net/Downloads.ashx
  • PdfDocument test = new PdfDocument (); test.Info.Title = "测试 PDF"; PdfPage page = test.AddPage(); XGraphics 图 = XGraphics.FromPdfPage (page); XFont font = new XFont("Verdana", 20, XFontStyle.Bold); graph.DrawString(strPairs, font, XBrushes.Black, new XRect(0, 0, page.Width.Point, page.Height.Point), XStringFormats.Center);字符串 pdfFilename = "testPairs.pdf"; test.Save(pdf文件名); Process.Start(pdf文件名);
  • 返回的内容是pdf结构。 OP 只是不知道如何将该内容保存到磁盘。除非 OP 还需要帮助以编程方式创建 PDF 文件,否则 pdf 库对此毫无帮助。
【解决方案3】:

首先从 NewResponse 创建 StreamReader

Stream receiveStream = NewResponse.GetResponseStream ();
StreamReader readStream = new StreamReader (receiveStream, Encoding.UTF8);

然后定义一个 StremaWriter 写入文件。

using (var writer = new StreamWriter(@"C:\MyNewFile.pdf", append: false))
{
    writer.Write(readStream.ReadToEnd());
}

替代方法是

var httpContent = NewResponse.Content; 

using(var newFile = System.IO.File.Create(@"C:\MyNewFile.pdf"))
{ 
    var stream = await httpContent.ReadAsStreamAsync();
    await stream.CopyToAsync(newFile);
}

【讨论】:

    【解决方案4】:

    这是我所做的,没有找到任何其他满足我情况的解决方案:

    using (var client = new System.Net.Http.HttpClient())
    
    {
      client.DefaultRequestHeaders.Add("Authorization", "someapikey");
      client.BaseAddress = new Uri("https://someurl.com");
      byte[] bytes = client.GetByteArrayAsync(client.BaseAddress).ConfigureAwait(false).GetAwaiter().GetResult();
    
      
      string pdfFilePath = @"c:\somepath"
      System.IO.File.WriteAllBytes(pdfFilePath, bytes);
    
      //Note that below is only to open PDF in standard viewer, not necessary
      var process = new System.Diagnostics.Process();
      var startInfo = new System.Diagnostics.ProcessStartInfo()
    {
        FileName=pdfFilePath,
        WorkingDirectory = System.IO.Path.GetDirectoryName(pdfFilePath),
        UseShellExecute = true
    }
    
      process.StartInfo = startInfo;
      process.Start();
    
    }
    

    【讨论】:

      【解决方案5】:

      使用此代码从 API 下载 pdf。它将字符串数据转换为字节,并为您提供必要的解决方案。

      HttpWebRequest request = (HttpWebRequest) WebRequest.Create(URL);
      
      request.ContentType = "application/pdf;charset=UTF-8";
      request.Method = "GET";
      
      using(HttpWebResponse response = (HttpWebResponse) request.GetResponse()) {
      
          BinaryReader bin = new BinaryReader(response.GetResponseStream());
      
          byte[] buffer = bin.ReadBytes((Int32) response.ContentLength);
      
          Response.Buffer = true;
          Response.Charset = "";
      
          Response.AppendHeader("Content-Disposition", "attachment; filename=+ filename); 
      
          Response.Cache.SetCacheability(HttpCacheability.NoCache);
      
          Response.ContentType = "application/pdf";
      
          Response.BinaryWrite(buffer);
      
          Response.Flush();
      
          Response.End();
      }
      

      【讨论】:

      • 我喜欢看到新参与者的贡献,但我鼓励您在发布之前测试您的解决方案。这不会编译,更不用说工作了。我建议修复它以使其正常工作。它最终可能成为这个问题的有价值的答案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-24
      • 2020-12-18
      • 2022-06-28
      • 2012-02-24
      • 1970-01-01
      • 2015-01-25
      相关资源
      最近更新 更多