Foxit PDF SDK for Web

How to create a real-time web chat with PDF chat history in JavaScript

Microsoft ASP.NET Core SignalR is an open-source library that simplifies adding real-time web functionality to web applications. Real-time web functionality enables server-side code to push content to clients instantly. Gaming, social networks, email client and chat are the most commonly applications which require real-time notifications and updates.

Many corporate and online shopping web sites now embed real-time chat to connect buyers, sellers, and service providers. This creates more opportunities for sellers to connect with potential buyers and win more business. To start developing a real-time chat application, we can take a sample SignalR application online. However, one concern of developing an online chat with SignalR is the loss of conversation history. In this article, we are going to extend a SignalR chat sample application and allow saving of the conversation history in PDF with JavaScript. Here, we are going to make use of a JavaScript PDF Library for Web Application – Foxit’s Web-based JavaScript PDF SDK. You can download a free trial here.

This article was written with the following tools:

  1. Microsoft Visual Studio 2019
  2. ASP.Net Core MVC with c#
  3. Foxit PDF SDK 7.2

Below shows the step-by-step guide to add a web PDF viewer to the SignalR Instant Messaging web application.

A. Download Chat Application

1) Download ASP.Net Core MVC 3.0 SignalR samples from

2) After extracting the archive, open the Chat Sample Visual Studio solution by opening the ChatSample.sln file in ChatSample folder.

3) Click Ctrl+F5 to run the application. When the browser opens, a dialog pops up to ask for a name. Provide a name and click “OK” to continue.

4) To simulate two users chatting with each other, open another web browser with the same URL.

5) Using the two web browsers to enter some messages. You can see the message sent from one browser appears in another web browser in real-time.

B. Adding Foxit Web PDF SDK

1) Download Foxit PDF SDK for Web here. Copy the content of the Lib folder in downloaded Foxit Web PDF SDK to the wwwroot\Lib folder of the SignalR Chat Sample web application folder.

2) Foxit Web SDK supports a compressed data stream which requires the server to support the file extension “brotli“. In order to do so, we are going to create an instance of the FileExtensionContentTypeProvider class. It contains a Mappings property to map the file extensions to MIME content types. We then invoke the UseStaticFiles method within Startup.Configure to add the mapping configuration to the application, as below:

using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting;
using System.IO;
namespace ChatSample
    public class Startup
      public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
            // Set up custom content types - associating file extension to MIME type
            var provider = new FileExtensionContentTypeProvider();
            // Add new mappings
            provider.Mappings[".brotli"] = "application/x-msdownload";
            app.UseStaticFiles(new StaticFileOptions
                FileProvider = new PhysicalFileProvider(
                    Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "lib/jr-engine/gsdk/")),
                RequestPath = "/lib/jr-engine/gsdk",
                ContentTypeProvider = provider


C. Export Chat History with PDF Web Viewer

1) First, we add a “js” sub-folder under wwwroot folder to store application JS files.

2) Copy the license-key.js from the example folder of the Foxit Web PDF SDK archive into the new js folder of the ChatSample application. This file contains the license key information which is required to use Foxit Web PDF SDK.

3) Next, we are going to prepare a PDF file as a template file for PDF file generation. This template will be used to store the chat history. Add a new folder “template” under wwwroot.

4) We then prepare a PDF file and store it in this template folder.

5) Next, we are going to add a HTML button to the Chat web page to export the chat history. Also a hidden <div> which is for rendering the chat history PDF file to be downloaded to the web browser.

6) We are going to store our script in a separate file “pdf.js”. Put this new file under the “js” folder we created earlier. We are going to make script references to this new script file, the license file and the PDF File Viewer js file.

7) Then add a new “pdf.js” JavaScript file in the Visual Studio solution.

8) Next, initialize the PDF Viewer Control.

var PDFViewer = PDFViewCtrl.PDFViewer;
var pdfViewer = new PDFViewer({
    libPath: '/lib',
    jr: {
        licenseSN: licenseSN,
        licenseKey: licenseKey,
        tileSize: 300

9) Then we are going to load the Chat History PDF template file we added earlier from the template folder to the PDF Viewer Control.

var xhr = new XMLHttpRequest();'GET', '/template/chat.pdf', true);
xhr.responseType = 'blob';
xhr.onreadystatechange = function () {
    if (xhr.readyState !== 4) {
    var status = xhr.status;
    if ((status >= 200 && status < 300) || status === 304) {
        pdfViewer.openPDFByFile(xhr.response).catch(function (e) {
            if (e.error === 11 && e.encryptDict.Filter === 'FOPN_foweb') {
                var fileOpenKey = getFileOpenKey(e.encryptDict);
                pdfViewer.reopenPDFDoc(e.pdfDoc, {
                    fileOpen: {
                        encryptKey: fileOpenKey

10) Then we define a function to save the content of the PDF Viewer into a physical file.

var saveByteArray = (function () {
    var a = document.createElement("a");
    document.body.appendChild(a); = "display: none";
    return function (data, name) {
        var blob = new Blob(data, { type: "octet/stream" }),
            url = window.URL.createObjectURL(blob);
        a.href = url; = name;;

11) Lastly, we create an event handler for the exportButton click event. It takes the content of the chat history on the web page, replaces the HTML element to avoid being rendered into the PDF file, creates an annotation object and adds it to the PDF document which we rendered in the PDF Viewer Control, and saves the document as a physical file.

document.getElementById('exportButton').onclick = function () {
    var content = document.getElementById("discussion").innerHTML
        .replace(/<\/li><li>/g, '\r\n \r\n')
        .replace(/&nbsp;/g, ' ')
        .replace(/<strong>/g, '')
        .replace(/<\/strong>/g, '')
        .replace(/<li>/g, '')
        .replace(/<\/li>/g, '');
    var annot = {
        "style": "solid",
        "width": 1,
        "contents": content,
        "opacity": 1,
        "color": "#FFFFFF",
        "flags": "print",
        "name": "e1005af7-f4a5-4186-90e1-121178a41962",
        "rotate": 0,
        "rect": "30,50,580,700",
        "subject": "Chat",
        "type": "freetext",
        "title": "Johnny Poon",
        "fontColor": "#000000",
        "page": 0
    pdfViewer.getCurrentPDFDoc().importAnnotsFromJSON([annot]).then(function () {
        pdfViewer.getCurrentPDFDoc().extractPages([[Number(0), Number(0)]]).then((buffer) => {
            //buffer:Array buffer of PDF document
            saveByteArray(buffer, 'history.pdf');

12) The whole PDF file is as below:

D. Running the resulting Chat application

1) When you now run the real-time chat application, you can see there is a Export Chat History button.

2) Clicking on the button you can see a history.pdf file downloaded. Opening the PDF can see the chat history is exported as annotation in the PDF file.

In this article, we extended a Microsoft ASP.Net Core MVC 3.0 SignalR real-time chat sample app. We added an Export button, a hidden PDF Web Viewer, and exported the content of chat history into a PDF template which was loaded into the hidden viewer for chat history PDF file generation.

Updated on August 16, 2021

Was this article helpful?
Thanks for your feedback. If you have a comment on how to improve the article, you can write it here: