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
Step 2: Install Microsoft.AspNet.WebApi from NuGet
Step 3: Install ‘PDFsharp-MigraDoc-GDI’ from NuGet:
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