简体   繁体   中英

Download PDF File from API Using C#

I am creating a console application that

  1. Connects to a vendor API to pull voucher numbers for submitted expenses between two dates and
  2. Downloads a PDF copy of receipts submitted with the expense

The first part, I have working fine. I am able to connect to the Vendor API and parse out the returned XML to create an array of voucher numbers (needed to get the PDF images) using the following code:

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);

Yes, there is likely a better way of doing this, but it works and returns the values I am expecting.

Now, what I am having trouble with, is when I connect back to the API to retrieve the file, I cannot seem to be able to download the file to a specified file path.

I can connect back to the API using

            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();

But I cannot seem to write the response to a valid file (PDF)

Here is a screen shot of my Autos window as I step through the code, where I would need to download the file:

汽车

My question is, from this point, how do I go about saving the file to my system?

I have tried to take the encoded response I get from doing Console.WriteLine(NewResponseString); and write it to a file using the System.IO.File.WriteAllLines() method, using a specified filepath/name, but this results in a blank file. I have also spent some time researching the depths of Google/Stackoverflow, but do not understand how to implement the results I find.

Any and all help would be greatly appreciated.

So I think you need help with Streams. The returned HttpContent is actually a System.Net.Http.StreamContent instance which shows that you are getting content back. Its just a matter of getting the Stream (content) from that instance and saving that to a file.

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
}

I respectfully recommend that you do a little reading on how Streams work. This is a common construct in many languages that you will probably have to deal with again in the near future.

First of all, are you sure there is a file to begin with? May I suggest using the open source library PdfSharp. I personally use it myself and it works great. As far as downloading the file, maybe this may help you...

Download Synchronously

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

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

At first Create StreamReader from NewResponse

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

Then Define a StremaWriter to write into a file.

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

Alternative Approach is

var httpContent = NewResponse.Content; 

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

Here is what I did, did not find any other solution that satisfied my situation:

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();

}

Use this code for download a pdf from the API. It will convert the string data to bytes and provide you the necessary solution.

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();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM