A very popular and useful way to access document processing functionality from a variety of applications and clients is to implement a Web API to create documents. Document generation can be a complex and time-consuming task, depending on the size and data structure of the template.
This task can take several seconds or even minutes when creating documents with many nested merge blocks and 100s or 1000s of pages. A typical document such as an invoice (which takes about 300 ms) could be created on the fly and returned by the HTTP request immediately after generation. However, requests that are longer than that (in the range of seconds) should be handled in a different way.
Creating a RESTful Web API that is called with a WebHook URL that receives a notification with a download link when the document is successfully created is one way to solve this problem.
How to design and implement this is discussed in another article. This article discusses the implementation of the WebHook and the invocation of the asynchronous Web API.
This sample shows how to build an asynchronous, RESTful Web API that calls a WebHook after the document generation process is terminated.
In this article, we are going to add another layer to this concept. Document generation requests are queued in a database and a background task using IHostedService is scheduled to generate documents.
IHostedService Background Tasks
Background tasks are application elements that work behind the scenes without end-user input or interaction. They typically involve processes that take a long time to complete or require the host application to keep updating parameters. In other words, it is the perfect application for time-consuming document creation tasks.
The client sends an HttpPost request to an endpoint that immediately returns a positive response if the request is acceptable. This request does not generate the document, but places the request in a queue.
The following code creates a unique URL where the document can be retrieved after it is created, and places the request in the queue.
We implement the BackgroundGenerator class, which is inherited from IHostedService.
In the Worker class, the DoWork method looks for requests in the queue and processes existing requests. The worker waits one second before the next round if no requests are found in the queue.
Once the document is created, the resulting file is stored in a database and a request is made to the WebHookUrl endpoint specified by the original client request. Basically, the request tells the consumer where to download the document once creation is complete.
The WebHook endpoint must be implemented by the calling client application and retrieves a URL where the completed document can be downloaded.
This endpoint will retrieve the document from the database on the basis of the given ID and will return the document.
The Sample Setup
In order to demonstrate this concept, the sample solution is made up of two separate projects:
The asynchronous Web API with the Background Worker.
A consuming application that calls the Web API and implements the WebHook.
For demonstration purposes, the solution has two initial projects. After compiling and starting the application, two browser windows are opened.
One browser will open the Web API with Swagger support, and the other browser that is open will display the consumer application. The consumer application consists of nothing more than a button that makes a call to the Web API using an AJAX HttpGet request.
In the following screenshot you can see three windows, the consuming application, the output folder where the PDFs are stored, and the .NET console with the status logs.
Each time the user clicks the button, the request is added to the queue, and the background worker picks up requests from the queue and returns the PDF, which is then stored locally.
The Web API application and its responsiveness are not affected by the actual document generation.