In this article, you will learn how to sign a document and export it as a PDF using Angular and an ASP.NET Core backend. Using TX Text Control .NET Server for ASP.NET and the Document Viewer for Angular, the electronic signature is captured and applied to a signature field that is digitally signed with a certificate to ensure that your documents are secure and reliable.

TX Text Control provides all the necessary capabilities to capture signatures from end users and process the document to create a fully signed and secure PDF document. It provides the server-side API to generate the PDF and the front-end UI tools for a modern, reliable and effortless signature experience.

Signature Support

TX Text Control provides two different types of signatures: Electronic signatures and digital signatures.

  • Electronic Signature
    An electronic signature is a signature that is captured using a touch screen or a mouse. It is a visual representation of a signature that is placed on a document. It is not necessarily cryptographically secured, but can be digitally signed.
  • Digital Signature
    A digital signature is a cryptographic signature that is applied to a document. It is cryptographically secured and ensures that the document has not been tampered with. It is based on a certificate that is issued by a trusted authority.

In most typical scenarios, the two types are combined so that visual signature fields contain the visual representation and are digitally signed with a certificate.

Document Viewer for Angular

The Document Viewer for Angular is a modern, web-based document viewer that is available for many platforms and provides all the functionality needed to capture signatures.

  • Out-of-the-box UI
    The Document Viewer for Angular provides a ready-to-use UI to display and sign documents. It is customizable and can be integrated into any Angular application.

    Angular Document Viewer UI

  • Signature Fields
    The Document Viewer for Angular provides support for signature fields that can be placed on the document to capture electronic signatures. These fields can be digitally signed with a certificate to ensure that the document is secure and reliable.

    Angular Document Viewer Signature Fields

  • Form Filling
    The Document Viewer for Angular provides support for form fields that can be placed on the document to capture data. These fields can be exported as a PDF form.

    Angular Document Viewer Forms Filling

  • Draw, Type or Upload Signatures
    The Document Viewer for Angular provides different ways to capture signatures. Users can draw, type or upload a signature image to sign the document.

    Angular Document Viewer Signature Capture

Prerequisites

In order to get started, you will need the following components:

npm and Angular command-line interface (CLI)

The client-side part of this tutorial can also be built independently of Visual Studio using the Angular CLI. To learn how to create an Angular CLI application using the TX Text Control, read this article.

Getting Started: Document Editor with Angular CLI v17.0

Creating the Application

The following tutorial will show you how to create an Angular with ASP.NET Core application that includes the client-side npm package and the required backend middleware.

  1. In Visual Studio 2022, create a new project, select Angular with ASP.NET Core as the project template and continue with Next.

    ASP.NET Core with Angular application

  2. Select a project name and location confirm with Next.

  3. Choose .NET 8 (Long Term Support) as the Framework, enable Use Controllers and continue with Create.

    ASP.NET Core with Angular application

Adding NuGet Packages

  1. Right-click on the project that ends with .Server in the Solution Explorer and select Manage NuGet Packages....

    Select Text Control Offline Packages from the Package source drop-down.

    Install the latest versions of the following packages:

    • TXTextControl.TextControl.ASP.SDK
    • TXTextControl.Web.DocumentViewer

    NuGet Packages

  2. Switch the package source to nuget.org and choose Installed to check for available updates. Update the installed packages to the most current version.

Preparing the Pipeline

  1. Open the file Program.cs in the .Server project and a replace the complete code with the following code:

    using TXTextControl.Web.MVC.DocumentViewer;
    var builder = WebApplication.CreateBuilder(args);
    // adding CORS policy to allow all origins
    builder.Services.AddCors(options =>
    {
    options.AddDefaultPolicy(
    builder =>
    {
    builder.AllowAnyOrigin()
    .AllowAnyMethod()
    .AllowAnyHeader();
    });
    });
    // Add services to the container.
    builder.Services.AddControllers();
    var app = builder.Build();
    app.UseDefaultFiles();
    app.UseStaticFiles();
    // Configure the HTTP request pipeline.
    app.UseHttpsRedirection();
    app.UseAuthorization();
    app.UseRouting();
    // adding CORS middleware
    app.UseCors();
    app.UseTXDocumentViewer();
    app.MapControllers();
    app.MapFallbackToFile("/index.html");
    app.Run();
    view raw test.cs hosted with ❤ by GitHub

Adding npm Packages

The Angular application has already been created by the Visual Studio project template and is available in the Solution Explorer ending with .client.

  1. In the Solution Explorer, expand the Angular application node, right-click npm, and select Install new npm packages from the context menu.

    Install new npm packages

  2. Search for @txtextcontrol/tx-ng-document-viewer and install the package. Add --legacy-peer-deps as a Other npm arguments to force the installation for newer Angular versions.

    Install @txtextcontrol/tx-ng-document-viewer

  3. Open the file src -> app -> app.module.ts, add replace the complete content with the following code and save it:

    import { HttpClientModule } from '@angular/common/http';
    import { NgModule } from '@angular/core';
    import { BrowserModule } from '@angular/platform-browser';
    import { AppRoutingModule } from './app-routing.module';
    import { AppComponent } from './app.component';
    import { DocumentViewerModule } from '@txtextcontrol/tx-ng-document-viewer';
    @NgModule({
    declarations: [
    AppComponent
    ],
    imports: [
    BrowserModule, HttpClientModule,
    AppRoutingModule, DocumentViewerModule
    ],
    providers: [],
    bootstrap: [AppComponent]
    })
    export class AppModule { }
    view raw test.ts hosted with ❤ by GitHub

Creating the Self-Signed Certificate

In the next steps, a self-signed certificate is created using Windows PowerShell.

  • Use the New-SelfSignedCertificate PowerShell cmdlet to create a self signed certificate. Open a PowerShell and type in the following command:

    New-SelfSignedCertificate -Type Custom -Subject "CN=Text Control, O=Text Control, C=US" -KeyUsage DigitalSignature -FriendlyName "TextControlSelf" -CertStoreLocation "Cert:\CurrentUser\My" -TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.3", "2.5.29.19={text}")
    view raw Powershell.ps hosted with ❤ by GitHub

    After running this command, the certificate is added to the certificate store (specified in the "-CertStoreLocation" parameter). The output of the command shows the certificate's thumbprint.

    PSParentPath: Microsoft.PowerShell.Security\Certificate::CurrentUser\My
    Thumbprint Subject
    ---------- -------
    6BA35B742656FB2EC48B09116ABAE5123082F116 CN=Text Control, O=Text Control, C=US
    view raw Powershell.ps hosted with ❤ by GitHub
  • Copy this thumbprint and insert it into the following command:

    $password = ConvertTo-SecureString -String yourpassword -Force -AsPlainText
    Export-PfxCertificate -cert "Cert:\CurrentUser\My\6BA35B742656FB2EC48B09116ABAE5123082F116" -FilePath textcontrolself.pfx -Password $password
    view raw Powershell.ps hosted with ❤ by GitHub
  • The file textcontrol_self.pfx is created in the same folder. Copy this to your application's folder from where you want to load the certificate (App_Data in our Web API sample above).

Creating the Controller

  1. Right-click on the Controllers folder in the .Server project and select Add -> Controller.... Choose MVC Controller - Empty and confirm with Add. Name it DocumentController and click Add.

  2. Replace the complete content of the DocumentController.cs with the following code:

    using Microsoft.AspNetCore.Mvc;
    using System.Security.Cryptography.X509Certificates;
    using TXTextControl;
    using TXTextControl.Web.MVC.DocumentViewer;
    using TXTextControl.Web.MVC.DocumentViewer.Models;
    namespace MyAngularBackend.Server.Controllers
    {
    [ApiController]
    [Route("[controller]")]
    public class DocumentController : ControllerBase
    {
    private readonly ILogger<DocumentController> _logger;
    public DocumentController(ILogger<DocumentController> logger)
    {
    _logger = logger;
    }
    [HttpGet]
    [Route("Load")]
    public DocumentData Load()
    {
    // open file as byte and convert to base64
    byte[] fileBytes = System.IO.File.ReadAllBytes("App_Data/document.tx");
    string file = Convert.ToBase64String(fileBytes);
    return new DocumentData { Name = "document.pdf", Document = file };
    }
    [HttpPost]
    [Route("Sign")]
    public string Sign([FromBody] SignatureData signatureData)
    {
    byte[] bPDF;
    // create temporary ServerTextControl
    using (ServerTextControl tx = new ServerTextControl())
    {
    tx.Create();
    // load the document
    tx.Load(Convert.FromBase64String(signatureData.SignedDocument.Document),
    BinaryStreamType.InternalUnicodeFormat);
    // create a certificate
    X509Certificate2 cert = new X509Certificate2("App_Data/textcontrol_self.pfx", "123");
    // create a list of digital signatures
    var signatureFields = new List<DigitalSignature>();
    // create a digital signature for each signature box
    foreach (SignatureBox box in signatureData.SignatureBoxes)
    {
    signatureFields.Add(new DigitalSignature(cert, null, box.Name));
    }
    // create save settings
    SaveSettings saveSettings = new SaveSettings()
    {
    CreatorApplication = "Your Application",
    SignatureFields = signatureFields.ToArray()
    };
    // save the document as PDF
    tx.Save(out bPDF, BinaryStreamType.AdobePDFA, saveSettings);
    }
    // return as Base64 encoded string
    return Convert.ToBase64String(bPDF);
    }
    }
    }
    view raw test.cs hosted with ❤ by GitHub

Adding the Document Viewer

  1. Open the file src -> app -> app.component.ts and replace the complete content with the following code:

    import { HttpClient } from '@angular/common/http';
    import { Component, OnInit, HostListener } from '@angular/core';
    declare const TXDocumentViewer: any;
    interface DocumentData {
    document?: string;
    name?: string;
    }
    @Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrl: './app.component.css',
    })
    export class AppComponent implements OnInit {
    public documentData: DocumentData = {};
    constructor(private http: HttpClient) { }
    @HostListener('window:documentViewerLoaded', ['$event'])
    onDocumentViewerLoaded() {
    TXDocumentViewer.signatures.setSubmitCallback(function (data: string) {
    var element = document.createElement('a');
    element.setAttribute('href', 'data:application/pdf;;base64,' + data);
    element.setAttribute('download', "results.pdf");
    document.body.appendChild(element);
    element.click();
    })
    var signatureSettings = {
    showSignatureBar: true,
    redirectUrlAfterSignature: 'https://localhost:7275/document/sign',
    ownerName: 'Paul',
    signerName: 'Jacob',
    signerInitials: 'PK',
    signatureBoxes: [{ name: 'txsign', signingRequired: true, style: 0 }]
    };
    TXDocumentViewer.loadDocument(this.documentData.document, this.documentData.name, signatureSettings);
    }
    ngOnInit() {
    this.getDocument();
    }
    getDocument() {
    this.http.get<DocumentData>('/document/load').subscribe(
    (result) => {
    this.documentData = result;
    }
    );
    }
    title = 'myangularbackend.client';
    }
    view raw test.ts hosted with ❤ by GitHub
  2. Open the file src -> app -> app.component.html and replace the complete content with the following code:

    <tx-document-viewer width="800px"
    height="800px"
    basePath="https://localhost:7275"
    dock="Window"
    [toolbarDocked]="true"
    [showThumbnailPane]="true">
    </tx-document-viewer>
    view raw test.html hosted with ❤ by GitHub

    The port number in the code (in this case 7275) can be found in the Properties -> launchSettings.json file of your .Server application.

  3. Open the file src -> proxy.conf.js and replace the code with the following code:

    const PROXY_CONFIG = [
    {
    context: [
    "/document",
    ],
    target: "https://localhost:7275",
    secure: false
    }
    ]
    module.exports = PROXY_CONFIG;
    view raw test.js hosted with ❤ by GitHub

    Replace the port number with the appropriate port number, similar to the previous step.

Adding a Sample Document

  1. Download the sample document document.tx and save it to the App_Data folder of the .Server project. Create the folder, if it doesn't exist.

Running the Application

  1. Run the application by pressing F5 in Visual Studio. The application starts and the Document Viewer is loaded with the sample document.

    Running the application

  2. Click on the signature field to sign the document. The signature dialog is opened and the signature can be drawn, typed or uploaded.

  3. After signing the document, the signature is applied and the document is digitally signed with the certificate.

    Signed document

Workflow Explanation

The following is a step-by-step description of the signing process.

Loading the Document

When the application is started, the document is loaded from the server and displayed in the Document Viewer. This is done using an HttpGet method that retrieves the template from the server.

getDocument() {
this.http.get<DocumentData>('/document/load').subscribe(
(result) => {
this.documentData = result;
}
);
}
view raw test.js hosted with ❤ by GitHub

Server-side, the Load method returns the document to be loaded and returned as a base64-encoded string.

[HttpGet]
[Route("Load")]
public DocumentData Load()
{
// open file as byte and convert to base64
byte[] fileBytes = System.IO.File.ReadAllBytes("App_Data/document.tx");
string file = Convert.ToBase64String(fileBytes);
return new DocumentData { Name = "document.pdf", Document = file };
}
view raw test.cs hosted with ❤ by GitHub

Signing the Document

When all signature fields are signed, the Sign method is called. The implemented HttpPost endpoint Sign is requested by the Document Viewer after the signing process. In this method, a digital certificate is applied to the signed electronic signature representation using the SignatureFields property. This property specifies an array of DigitalSignature objects, each of which defines an X.509 certificate and is associated with a SignatureField in the document. These certificates can be used to digitally sign a PDF or a PDF/A file.

[HttpPost]
[Route("Sign")]
public string Sign([FromBody] SignatureData signatureData)
{
byte[] bPDF;
// create temporary ServerTextControl
using (ServerTextControl tx = new ServerTextControl())
{
tx.Create();
// load the document
tx.Load(Convert.FromBase64String(signatureData.SignedDocument.Document),
BinaryStreamType.InternalUnicodeFormat);
// create a certificate
X509Certificate2 cert = new X509Certificate2("App_Data/textcontrol_self.pfx", "123");
// create a list of digital signatures
var signatureFields = new List<DigitalSignature>();
// create a digital signature for each signature box
foreach (SignatureBox box in signatureData.SignatureBoxes)
{
signatureFields.Add(new DigitalSignature(cert, null, box.Name));
}
// create save settings
SaveSettings saveSettings = new SaveSettings()
{
CreatorApplication = "Your Application",
SignatureFields = signatureFields.ToArray()
};
// save the document as PDF
tx.Save(out bPDF, BinaryStreamType.AdobePDFA, saveSettings);
}
// return as Base64 encoded string
return Convert.ToBase64String(bPDF);
}
view raw test.cs hosted with ❤ by GitHub

The following diagram illustrates the signature workflow.

Signature Workflow

Conclusion

This tutorial showed how to create an Angular application with an ASP.NET Core backend that uses the Document Viewer to display and sign PDF documents. The Document Viewer provides all the necessary UI and API to capture signatures and to digitally sign the document with a certificate. The server-side API provides the necessary methods to load and save the document and to apply the digital signature.

Download the sample from GitHub and test the signature process with your own certificate.