Create PDF’s with ASP.NET Web Api

This blog describes how to generate PDF’s with ASP.NET Web Api using PdfSharp/MigraDoc.

 

Sample result:

http://servername/api/test.pdf?author=bert generates a pdf with  the authorname as parameter. This sample can be extended to create

complete dynamically  reports.

 

Sample code is available on https://github.com/bertt/DynamicPDF

 

Step 1: Generate new empty ASP.NET project with Visual Studio

image

Step 2: Install Microsoft.AspNet.WebApi from NuGet

image

Step 3: Install ‘PDFsharp-MigraDoc-GDI’ from NuGet:

image

 

Step 4: Change web.config

Add the following to in web.config file in the system.webServer section:

 

<modules runAllManagedModulesForAllRequests="true"/>

 

This is needed because otherwise the IIS webserver will search for a static PDF file and not a dynamic one generated by ASP.NET.

 

Step 5: Add global.asax with the following content:

 

    public class Global : System.Web.HttpApplication
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.Ignore("{resource}.axd/{*pathInfo}");

            routes.MapHttpRoute(
                name: "IdWithExt",
                routeTemplate: "api/{controller}.{ext}");

            routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }

        protected void Application_Start(object sender, EventArgs e)
        {
            RegisterRoutes(RouteTable.Routes);

            var pdfFormatter = new PdfMediaTypeFormatter();
            GlobalConfiguration.Configuration.Formatters.Add(pdfFormatter);
        }
    }

In the Global.asax we register the PDF Mediatypeformatter, defined in the next step.

 

Step 6: Add a Mediatype formatter for PDF 

Add a new class ‘PdfMediaTypeFormatter’. This class overrides from MediaTypeFormatter. Important is the ‘SupportedType’, only controllers

who return the SupportedType will use this formatter. Another important parameter is the ‘object value’ in the WriteToStreamAsync method. This parameter

contains the specified PDF parameter (in our case the author name).

 

   public class PdfMediaTypeFormatter : MediaTypeFormatter
    { 
       private static readonly Type SupportedType = typeof(Person); 

       public PdfMediaTypeFormatter()
        {
            SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/pdf"));
            MediaTypeMappings.Add(new UriPathExtensionMapping("pdf", "application/pdf"));
        } 

       public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, System.Net.Http.HttpContent content, TransportContext transportContext)
        { 
           var taskSource = new TaskCompletionSource<object>(); 
           try 
           { 
               var person = (Person)value; 

               var doc = PdfGenerator.CreatePdf(person.Name); 
               var ms = new MemoryStream();

                doc.Save(ms, false); 

               var bytes = ms.ToArray();
                writeStream.Write(bytes, 0, bytes.Length);
                taskSource.SetResult(null);
            } 
           catch (Exception e)
            {
                taskSource.SetException(e);
            } 
           return taskSource.Task;
        } 

       public override bool CanReadType(Type type)
        { 
           return SupportedType == type;
        } 

       public override bool CanWriteType(Type type)
        { 
           return SupportedType == type;
        }

Step 7:  Add a simple test controller class.

 

 

This controller returns a Person class, which will be rendered using the PDF Media Type.

    public class TestController:ApiController
    {
        public HttpResponseMessage GetTest(string author)
        {
            var person=new Person{Name=author};
            return Request.CreateResponse(HttpStatusCode.OK,person);
        }
    }
 

Step 8: Add a Person class

    public class Person
    {
        public String Name { get; set; }
    }

Step 9: Add code to generate a PDF (class PdfGenerator).

 

This code creates an in-memory PDF and returns it.

 

    public static class PdfGenerator
    {
        public static PdfDocument CreatePdf(string author)
        {
            var document = new Document();
            var sec = document.Sections.AddSection();
            sec.AddParagraph("Author:" + author);
            return RenderDocument(document);
        }

        private static PdfDocument RenderDocument(Document document)
        {
            var rend = new PdfDocumentRenderer {Document = document};
            rend.RenderDocument();
            return rend.PdfDocument;
        }
    }

 

Step 10: Test!

Run the project and open http://localhost:64118/api/test.pdf?author=piet

A PDF file with the specified authorname will be returned if all goes well

 

image