This article will walk through the steps to programmatically create a PDF file using DotPdf, stream it to a client computer, then parse the data upon the client’s submission.
What you will need
- Atalasoft DotPdf
If you do not have DotPdf you can download the installer here. http://www.atalasoft.com/products/dotpdf/
- Atalasoft DotPdf License
Use the Activate DotPdf application in your start menu to generate a DotPdf license. If you deploy your application to IIS you will need to get a server license and put it in your bin folder of the application.
- Visual Studio Standard C# IDE
Create a Web Project with handler
Open Visual Studio and create a new project. Select .ASP web application as the project type. Add two New Items to your project, a HTML page and a Generic Handler named PdfHandler.ashx. Set the HTML page as the start page for your application. The PdfHandler.ashx is where you will put all of the backend code for this project.
Generating a PDF form
First we will need to generate the PDF form. DotPdf has a class called
PdfGeneratedDocument it is the starting point to generate a document. The document will also be storing our
PdfForm object and contains any number of
PdfPage objects. Using the following three method calls we will initialize the document to have a page and a form:
PdfGeneratedDocument doc = new PdfGeneratedDocument();
doc.Form = new Atalasoft.PdfDoc.Generating.Forms.PdfForm();
PdfGeneratedPage page = doc.AddPage(PdfDefaultPages.Letter);
Next, we will create a data field for the client to submit text data. This is done with a
TextWidgetAnnotation. To label the field we will use a
PdfTextLine. Remember that PDF coordinates are drawn from the bottom left of the page with each inch being represented by 72 PDF points. To put the text annotation near the top of the document, I chose 700 for the Y component and generated the following code:
TextWidgetAnnotation name = new TextWidgetAnnotation(
new PdfBounds(72, 700, 200, 20), "name", null);
PdfTextLine nameLabel = new PdfTextLine(
"Helvetica", 22.0, "Name:", new PdfPoint(72, 730));
Note: Using Helvetica for the
PdfTextLine’s font allows you to not have to create a
PdfFontResource. If you wish to have a custom font, you will need to create a
PdfFontResource and add it to the document.
Once the objects are created, they will need to be added to the appropriate rendering lists. The
PdfTextLine will need to be added to the page’s drawing list. Because the
TextWidgetAnnotation is an annotation and part of our form, we will need to add it to both the annotation list and the form object.
The other form element is the submit button. When the client clicks the submit button, we want the PDF form to send a post request to our webhandler. Just like the other annotation, we need to give it a position. To make this a submit button we must give it a
PdfSubmitFormAction initialized with URL that it will post to, and
SubmitAsHtml set to true. Then we add it to the Form and Annotations collections:
PushButtonWidgetAnnotation button = new PushButtonWidgetAnnotation(
new PdfBounds(72, 550, 60, 20), "submit");
PdfSubmitFormAction submit = new PdfSubmitFormAction(context.Request.Url);
submit.SubmitAsHtml = true;
I recommend then wrapping all the PDF generation code in a method call
Streaming the PDF to the client
To then stream the generated PDF to the client, we write the document out to the
Context.Response.OutputStream. The following code will allow for the document to be streamed to the client and automatically opened in the adobe plugin or chromes PDF viewer:
private void SendPdfForm(HttpContext context)
context.Response.ContentType = "application/pdf";
context.Response.AddHeader("Content-Disposition", "inline; filename=" + "PDFForm");
PdfGeneratedDocument doc = CreatePdf(context);
MemoryStream mem = new MemoryStream();
byte pdfBytes = new byte[mem.Length];
mem.Read(pdfBytes, 0, (int)(mem.Length));
Routing the requests to the proper functions
In the ashx file, when it was generated, there is a method stub for
ProcessRequest. This is where all of the requests to PdfHandler.ashx will be routed to. Due to the nature of our application, two different requests will be made of the handler: one to request the programmatically generated PDF and one to handle the PDF form submission. PDF form submission will always have information in the input stream. To distinguish when one of these calls is made I use the following code:
if (context.Request.InputStream.Length !=0)
To distinguish a request for the PDF we can access a hidden form value though the query string like this:
Requesting the PDF though HTML
In your HTML document, sending a request to the server for the dynamically generated PDF is simple. Make a HTML form with a submit button and a hidden data value (this will get consumed as a query string):
<input type="hidden" name="pdf" value="request" />
<input type="submit" id="Button1" value="Get Pdf Form" />
If you were to debug your application at this point, place a breakpoint on the
SendPdfForm method call in your
ProcessRequest method. If you press the button on your HTML page you should cause the breakpoint to trigger. After continuing you should be presented with a PDF document (assuming you are using Chrome or have Adobe Acrobat installed and plugged into your browser).
Handling the PdfForm POST request
Once the PDF is successfully streaming to the client, submit a form with the name field filled in and the InputStream of the resulting request to your webserver will contain an HTML query string style data pairing string (e.g.
"name=Jeff&DOB=12021985"). There is a built in static .NET method to parse this style of return data into a
NameValueCollection: it is
HttpUtility.ParseQueryString(string). That data can then be processed into your solution in whatever way your workflow is designed.