How to Create a Custom Submittable PDF Form and Capture User Input From It

April 7, 2015 Atalasoft General

This tutorial will demonstrate the steps to programmatically create a PDF form using DotPdf, stream it to a client computer through a website, then parse the data upon the client’s submission. The application will be broken into two parts: delivering a PDF with form elements created on the fly, and then extracting data submitted from the PDF.  The data will be submitted back to the application using a POST.

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 outside of visual studio 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 we'll choose 700 for the Y component and generate 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, one is automatically provided instead. 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.

page.DrawingList.Add(nameLabel);
page.Annotations.Add(name);
doc.Form.Fields.Add(name);

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;
button.ClickActions.Add(submit);
page.Annotations.Add(button);
doc.Form.Fields.Add(button);

For ease of use, wrap all the PDF generation code in a method call CreatePdf(context).

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 Chrome's PDF viewer:

private void SendPdfForm(HttpContext context)
{
context.Response.Clear();
context.Response.ContentType = "application/pdf";
context.Response.AddHeader("Content-Disposition", "inline; filename=PDFForm");

PdfGeneratedDocument doc = CreatePdf(context);

MemoryStream mem = new MemoryStream();
doc.Save(mem);
mem.Seek(0, SeekOrigin.Begin);
byte[] pdfBytes = new byte[mem.Length];
mem.Read(pdfBytes, 0, (int)(mem.Length));
context.Response.AddHeader("Content-Length", pdfBytes.Length.ToString());
context.Response.BinaryWrite(pdfBytes);
context.Response.Flush();
context.Response.End();
}

Routing the requests to the proper functions

In the ashx file when it was generated there was 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 a header by the name “Acrobat-Version”. To distinguish when one of these calls is made we'll use the following code:

if (context.Request.Headers["Acrobat-Version"] != null)
HandleFormSubmission(context);

To distinguish a request for the pdf we can access a hidden form value though the query string like this:

if(context.Request.QueryString["pdf"]!=null)
SendPdfForm(context);

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

<body>
<form action="PdfHandler.ashx">
<input type="hidden" name="pdf" value="request" />
<input type="submit" id="Button1" value="Get Pdf Form" />
</form>
</body>

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 however it is desired.

 

About the Author

Atalasoft General

This is a general account for case studies, product information, and articles about the culture of Atalasoft.

Follow on Twitter More Content by Atalasoft General
Previous Article
How to Make PDF Your Imaging Format
How to Make PDF Your Imaging Format

How to Make PDF Your Imaging Format Benefits and how to get the job...

Next Article
Introduction to the DotPdf Template Page Generator
Introduction to the DotPdf Template Page Generator

The DotPdf Template Page Generator is a tool designed to help you quickly...