Create or Generate PDF / Word and export in ASP.NET

GemBox.Document is a standalone .NET component with 100% managed code. It doesn't use Microsoft Office Interop nor any other dependency.

Its fast performance and thread safety when working with multiple DocumentModel objects makes it ideal for web applications (like ASP.NET Web Forms, ASP.NET MVC and ASP.NET Core).

The following example demonstrates how you can create an ASP.NET Web Forms application that executes a mail merge process on a template Word document, with data provided by web form, to generate a PDF file that's exported or downloaded to a client's browser.

Screenshot of Default.aspx page and submitted web form
Sending form data from default page of ASP.NET Web Forms demo application
Screenshot of created PDF file that's exported from ASP.NET application
Generated PDF document from template Word document in ASP.NET Web Forms demo application
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="MediumTrust.Default" %>

<!DOCTYPE html>
<html>
<head runat="server">
    <title>Create PDF documents or Word files (DOCX, RTF, XML, HTML) from ASP.NET Web Forms</title>
    <style>
        * {
            font-family: Calibri;
            color: #514E52;
            padding: 6px;
            box-sizing: border-box;
        }

        header {
            height: 80px;
            background: #F26522 url("./images/logo.svg") no-repeat left;
        }

        header a {
            height: 68px;
            display: block;
        }

        label, input, select, th, td { width: 150px; }

        label {
          display: inline-block;
          text-align: right;
        }

        label::after { content: ":"; }
        
        .aspNetHidden { padding: 0; }
    </style>
</head>
<body>
    <header><a href="https://www.gemboxsoftware.com/"></a></header>
    <form id="formInvoice" runat="server">
        <h1>Invoice</h1>
        <div>
            <asp:Label ID="lblNumber" runat="server" AssociatedControlId="txtNumber" Text="Number" />
            <asp:TextBox ID="txtNumber" runat="server" TextMode="Number" />
        </div>

        <div>
            <asp:Label ID="lblDate" runat="server" AssociatedControlId="txtDate" Text="Date" />
            <asp:TextBox ID="txtDate" runat="server" TextMode="Date" />
        </div>

        <div>
            <asp:Label ID="lblCompany" runat="server" AssociatedControlId="txtCompany" Text="Company" />
            <asp:TextBox ID="txtCompany" runat="server" TextMode="SingleLine" />
        </div>

        <asp:GridView ID="gridItems" runat="server" BorderColor="#BFBFBF" ShowHeaderWhenEmpty="true"
            AutoGenerateColumns="false" AutoGenerateDeleteButton="true" AutoGenerateEditButton="true"
            OnRowUpdating="gridItems_RowUpdating"
            OnRowEditing="gridItems_RowEditing"
            OnRowCancelingEdit="gridItems_RowCancelingEdit"
            OnRowDeleting="gridItems_RowDeleting">
            <HeaderStyle Font-Bold="true" Font-Size="Larger" />
            <Columns>
                <asp:BoundField DataField="Date" HeaderText="Date" DataFormatString="{0:d MMM yyyy}" />
                <asp:BoundField DataField="Hours" HeaderText="Hours" DataFormatString="{0:d}" />
                <asp:BoundField DataField="Unit" HeaderText="Unit (€/hour)" DataFormatString="{0:0.00}" />
                <asp:BoundField DataField="Price" HeaderText="Price" DataFormatString="{0:0.00}" ReadOnly="true" />
            </Columns>
        </asp:GridView>

        <div>
            <asp:Button ID="btnAddRow" runat="server" Text="Add Item" OnClick="btnAddRow_Click"/>
        </div>
        
        <div>
            <asp:Label ID="lblTotal" runat="server" AssociatedControlId="txtDate" Text="Total" Font-Bold="true" ForeColor="#F26522" Font-Size="Larger" />
            <asp:TextBox ID="txtTotal" runat="server" ReadOnly="true" Font-Bold="true" ForeColor="#F26522" Font-Size="Larger" />
        </div>

        <div>
            <asp:Label ID="lblFileFormat" runat="server" AssociatedControlId="ddlFileFormat" Text="File format" />
            <asp:DropDownList ID="ddlFileFormat" runat="server">
                <asp:ListItem Value=".docx">DOCX</asp:ListItem>
                <asp:ListItem Value=".pdf" Selected="true">PDF</asp:ListItem>
                <asp:ListItem Value=".html">HTML</asp:ListItem>
                <asp:ListItem Value=".mhtml">MHTML</asp:ListItem>
                <asp:ListItem Value=".rtf">RTF</asp:ListItem>
                <asp:ListItem Value=".xml">XML</asp:ListItem>
                <asp:ListItem Value=".txt">TXT</asp:ListItem>
            </asp:DropDownList>
        </div>

        <div>
            <asp:Button ID="btnCreateFile" runat="server" Text="Create Invoice" OnClick="btnCreateFile_Click" />
        </div>
    </form>
</body>
</html>
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Web.UI;
using System.Web.UI.WebControls;
using GemBox.Document;

namespace MediumTrust
{
    public partial class Default : Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            // If using Professional version, put your serial key below.
            ComponentInfo.SetLicense("FREE-LIMITED-KEY");

            // In order to create a PDF file in Medium Trust environment you'll need to specify
            // font files location that is under your ASP.NET application's control.
            // This is required because in partial-trust domain it's prohibited to access system's installed fonts.
            FontSettings.FontsBaseDirectory = Server.MapPath("Fonts/");

            // Set web form default values.
            if (!this.Page.IsPostBack)
            {
                this.txtNumber.Text = "10203";
                this.txtDate.Text = DateTime.Today.ToString("yyyy-MM-dd");
                this.txtCompany.Text = "ACME Corp";

                var items = new DataTable("Items");
                items.Columns.Add("Date", typeof(DateTime));
                items.Columns.Add("Hours", typeof(int));
                items.Columns.Add("Unit", typeof(double));
                items.Columns.Add("Price", typeof(double));

                items.Rows.Add(DateTime.Today.AddDays(-3), 6, 35);
                items.Rows.Add(DateTime.Today.AddDays(-2), 7, 35);
                items.Rows.Add(DateTime.Today.AddDays(-1), 8, 35);

                this.Session["ItemsTable"] = items;
                this.RefreshGridData();
            }
        }

        private DataTable GetGridData() => (DataTable)this.Session["ItemsTable"];

        private void RefreshGridData()
        {
            var items = this.GetGridData();

            double total = 0;
            foreach (DataRow row in items.Rows)
            {
                double price = (int)row["Hours"] * (double)row["Unit"];
                row["Price"] = price;
                total += price;
            }

            this.gridItems.DataSource = items;
            this.gridItems.DataBind();
            this.txtTotal.Text = total.ToString("0.00");
        }

        protected void btnCreateFile_Click(object sender, EventArgs e)
        {
            // Load template document.
            DocumentModel document = DocumentModel.Load(
                Path.Combine(this.Request.PhysicalApplicationPath, "%#InvoiceTemplate.docx%"));

            if (!int.TryParse(this.txtNumber.Text, out int number))
                this.txtNumber.Text = number.ToString();

            if (!DateTime.TryParse(this.txtDate.Text, out DateTime date))
                this.txtDate.Text = date.ToString();

            // Execute mail merge operations with data from web form.
            document.MailMerge.Execute(
                new Dictionary<string, object>()
                {
                    ["Number"] = number,
                    ["Date"] = date,
                    ["Company"] = this.txtCompany.Text,
                    ["TotalPrice"] = double.Parse(this.txtTotal.Text)
                });
            document.MailMerge.Execute(
                this.GetGridData());

            // Create document in specified format (PDF, DOCX, etc.) and
            // stream (download) it to client's browser.
            document.Save(this.Response, $"Invoice{this.ddlFileFormat.SelectedValue}");
        }

        protected void btnAddRow_Click(object sender, EventArgs e)
        {
            var items = this.GetGridData();
            items.Rows.Add(DateTime.Today, 8, 35);
            this.RefreshGridData();

        }

        protected void gridItems_RowUpdating(object sender, GridViewUpdateEventArgs e)
        {
            var items = this.GetGridData();

            int rowIndex = e.RowIndex;
            for (int columnIndex = 1; columnIndex < items.Columns.Count; columnIndex++)
            {
                var cell = this.gridItems.Rows[rowIndex].Cells[columnIndex];

                if (cell.Controls[0] is System.Web.UI.WebControls.TextBox textBox)
                {
                    try { items.Rows[rowIndex][columnIndex - 1] = textBox.Text; }
                    catch (ArgumentException) { }
                }
            }

            this.gridItems.EditIndex = -1;
            this.RefreshGridData();
        }

        protected void gridItems_RowEditing(object sender, GridViewEditEventArgs e)
        {
            this.gridItems.EditIndex = e.NewEditIndex;
            this.RefreshGridData();
        }

        protected void gridItems_RowCancelingEdit(object sender, GridViewCancelEditEventArgs e)
        {
            this.gridItems.EditIndex = -1;
            this.RefreshGridData();
        }

        protected void gridItems_RowDeleting(object sender, GridViewDeleteEventArgs e)
        {
            var items = this.GetGridData();
            items.Rows[e.RowIndex].Delete();
            this.RefreshGridData();
        }
    }
}
Imports System
Imports System.Collections.Generic
Imports System.Data
Imports System.IO
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports GemBox.Document

Namespace MediumTrust
    Partial Public Class [Default]
        Inherits Page

        Protected Sub Page_Load(sender As Object, e As EventArgs)

            ' If using Professional version, put your serial key below.
            ComponentInfo.SetLicense("FREE-LIMITED-KEY")

            ' In order to create a PDF file in Medium Trust environment you'll need to specify
            ' font files location that is under your ASP.NET application's control.
            ' This is required because in partial-trust domain it's prohibited to access system's installed fonts.
            FontSettings.FontsBaseDirectory = Server.MapPath("Fonts/")

            ' Set web form default values.
            If Not Page.IsPostBack Then
                Me.txtNumber.Text = "10203"
                Me.txtDate.Text = DateTime.Today.ToString("yyyy-MM-dd")
                Me.txtCompany.Text = "ACME Corp"

                Dim items As New DataTable("Items")
                items.Columns.Add("Date", GetType(DateTime))
                items.Columns.Add("Hours", GetType(Integer))
                items.Columns.Add("Unit", GetType(Double))
                items.Columns.Add("Price", GetType(Double))

                items.Rows.Add(DateTime.Today.AddDays(-3), 6, 35)
                items.Rows.Add(DateTime.Today.AddDays(-2), 7, 35)
                items.Rows.Add(DateTime.Today.AddDays(-1), 8, 35)

                Me.Session("ItemsTable") = items
                Me.RefreshGridData()
            End If

        End Sub

        Private Function GetGridData() As DataTable
            Return DirectCast(Me.Session("ItemsTable"), DataTable)
        End Function

        Private Sub RefreshGridData()

            Dim items = Me.GetGridData()

            Dim total As Double = 0
            For Each row As DataRow In items.Rows
                Dim price As Double = CInt(row("Hours")) * CDbl(row("Unit"))
                row("Price") = price
                total += price
            Next

            Me.gridItems.DataSource = items
            Me.gridItems.DataBind()
            Me.txtTotal.Text = total.ToString("0.00")

        End Sub

        ' On button click generate the document and stream it to the browser.
        Protected Sub btnCreateFile_Click(sender As Object, e As EventArgs)

            ' Load template document.
            Dim document As DocumentModel = DocumentModel.Load(
                Path.Combine(Me.Request.PhysicalApplicationPath, "%#InvoiceTemplate.docx%"))

            Dim number As Integer
            If Not Integer.TryParse(Me.txtNumber.Text, number) Then
                Me.txtNumber.Text = number.ToString()
            End If

            Dim [date] As DateTime
            If Not DateTime.TryParse(Me.txtDate.Text, [date]) Then
                Me.txtDate.Text = [date].ToString()
            End If

            ' Execute mail merge operations with data from web form.
            document.MailMerge.Execute(
            New Dictionary(Of String, Object) From
            {
                {"Number", number},
                {"Date", [date]},
                {"Company", Me.txtCompany.Text},
                {"TotalPrice", Double.Parse(Me.txtTotal.Text)}
            })

            document.MailMerge.Execute(
            Me.GetGridData())

            ' Create document in specified format (PDF, DOCX, etc.) and
            ' stream (download) it to client's browser.
            document.Save(Me.Response, $"Invoice{Me.ddlFileFormat.SelectedValue}")

        End Sub

        Protected Sub btnAddRow_Click(sender As Object, e As EventArgs)
            Dim items = Me.GetGridData()
            items.Rows.Add(DateTime.Today, 8, 35)
            Me.RefreshGridData()
        End Sub

        Protected Sub gridItems_RowUpdating(sender As Object, e As GridViewUpdateEventArgs)

            Dim items = Me.GetGridData()

            Dim rowIndex As Integer = e.RowIndex
            For columnIndex = 1 To items.Columns.Count - 1

                Dim cell = Me.gridItems.Rows(rowIndex).Cells(columnIndex)
                Dim textBox = TryCast(cell.Controls(0), System.Web.UI.WebControls.TextBox)
                If textBox IsNot Nothing Then
                    Try
                        items.Rows(rowIndex)(columnIndex - 1) = textBox.Text
                    Catch ex As ArgumentException
                    End Try
                End If
            Next

            Me.gridItems.EditIndex = -1
            Me.RefreshGridData()

        End Sub

        Protected Sub gridItems_RowEditing(sender As Object, e As GridViewEditEventArgs)
            Me.gridItems.EditIndex = e.NewEditIndex
            Me.RefreshGridData()
        End Sub

        Protected Sub gridItems_RowCancelingEdit(sender As Object, e As GridViewCancelEditEventArgs)
            Me.gridItems.EditIndex = -1
            Me.RefreshGridData()
        End Sub

        Protected Sub gridItems_RowDeleting(sender As Object, e As GridViewDeleteEventArgs)
            Dim items = Me.GetGridData()
            items.Rows(e.RowIndex).Delete()
            Me.RefreshGridData()
        End Sub

    End Class
End Namespace

GemBox.Document provides support for both full trust and medium trust environment. This example's demo is an ASP.NET Medium Trust application that is running in a partial-trust application domain.

Such applications have homogeneous domains that have a constrained set of possible permissions. For more information, visit our Support for Partially Trusted applications help page or Microsoft's ASP.NET Code Access Security documentation.

GemBox.Document is only licensed per developer and the licenses include a royalty-free deployment. There are no server or OEM licenses, there are no additional costs for anything (like building, testing and deploying).

So, you're free to build an unlimited number of applications and deploy or distribute them to an unlimited number of servers or end user machines with no extra cost.

Check next example or download examples from GitHub.