Vivek
Vivek

Reputation: 1

Save WebAPI response as PDF file

I have written WebAPI GET method which returns a file, I have checked SoapUI its working well. Now I want call that service and save the file as a PDF in local drive, I'm getting response from service but how I do convert response into file of PDF format?

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

It throws an exception Throwing exception on var output...

Error reading bytes. Unexpected token: StartObject. Path 'version', line 1, position 11

Response in 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
}

Upvotes: 0

Views: 10052

Answers (2)

AlwaysLearning
AlwaysLearning

Reputation: 8819

I think your main problem is trying to use ReadAsAsync<byte[]> from Microsoft.AspNet.WebApi.Client in your FileIndex() method:

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

This is intended to work with JSON responses. There are some links erroneously claiming you can make it work with application/octet-stream responses by adding the a line to your WebApiConfig.cs, such as:

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

I believe that advice is flawed, I've never been able to make it work. If you have that line in your project you should remove it and use the following in your FileIndex() method instead:

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

Here is a complete console application that consumes the application/pdf stream from a Web API method and saves it to disk (in the TestClient/bin/Debug folder next to the TestClient.exe file):

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

And here is a controller I implemented that demonstrates how to return a PDF file to the client with the proper MIME Type and other metadata information:

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

Hope this helps!

Upvotes: 4

Vladimir Arkhangelskii
Vladimir Arkhangelskii

Reputation: 120

You can use this example to explain your need.

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

}

Upvotes: -1

Related Questions