Products Technologies Demo Docs Blog Support Company

Designing a MailMerge Web API Endpoint with ASP.NET Core in C#

This article shows how to create a Web API endpoint that merges templates with JSON data using TX Text Control .NET Server Core. It shows how to design the endpoint to accept the template, the data, and settings for the merge process.

Designing a MailMerge Web API Endpoint with ASP.NET Core in C#

The MailMerge class provides very powerful document generation capabilities based on a template and JSON data to create MS Word DOCX files or PDF documents. You can specify settings such as removing blank spaces or empty fields during the merge process. But how do you design a Web API with all these options, and how do you pass the template and data to the endpoint?

Learn More

The MailMerge class provides very effective ways to merge data into MS Word compatible templates. This updated ultimate guide provides an overview of all the important features and functionalities of the mail merge process.

An Ultimate Guide to Mail Merge with MS Word Documents in C#

Designing the Web API

A typical merge process requires a template, data and settings for the MailMerge class, and additional settings for the generated PDF, such as author information.

Let's start with the Web API endpoint. The following code snippet shows the Web API endpoint that accepts a POST request with a JSON payload containing the template, data, and settings for the merge process.

public class DocumentController : Controller
{
  [HttpPost]
  public IActionResult Merge(
    [FromBody] MergeBody mergeBody)
  {

    #region Error Checking

    // error checking: MergeBody cannot be null
    if (mergeBody == null)
    {
      return BadRequest();
    }

    // error checking: Template must not be null
    if (mergeBody.Template == null)
    {
      return BadRequest("Template must not be null");
    }

    #endregion

    using (TXTextControl.ServerTextControl tx = new TXTextControl.ServerTextControl())
    {
      tx.Create();

      // load the template
      try {         
        tx.Load(Convert.FromBase64String(mergeBody.Template), TXTextControl.BinaryStreamType.InternalUnicodeFormat);
      }
      catch (Exception ex) // format not valid
      {
        return BadRequest(ex.Message);
      }

      // create a new MailMerge object
      MailMerge mailMerge = new MailMerge()
      {
        TextComponent = tx,
        
        // set the merge settings
        DataSourceCulture = new CultureInfo(mergeBody.MergeSettings.DataSourceCulture),
        FormFieldMergeType = (FormFieldMergeType)mergeBody.MergeSettings.FormFieldMergeType,
        MergeCulture = new CultureInfo(mergeBody.MergeSettings.MergeCulture),
        RemoveEmptyBlocks = mergeBody.MergeSettings.RemoveEmptyBlocks ?? false,
        RemoveEmptyFields = mergeBody.MergeSettings.RemoveEmptyFields ?? false,
        RemoveEmptyImages = mergeBody.MergeSettings.RemoveEmptyImages ?? false,
        RemoveEmptyLines = mergeBody.MergeSettings.RemoveEmptyLines ?? false,
        RemoveTrailingWhitespace = mergeBody.MergeSettings.RemoveTrailingWhitespace ?? false,
      };

      // merge the data
      mailMerge.MergeJsonData(mergeBody.MergeData, true);

      // save settings
      TXTextControl.SaveSettings saveSettings = new TXTextControl.SaveSettings()
      {
        Author = mergeBody.MergeSettings.Author,
        CreationDate = (DateTime)mergeBody.MergeSettings.CreationDate,
        CreatorApplication = mergeBody.MergeSettings.CreatorApplication,
        DocumentSubject = mergeBody.MergeSettings.DocumentSubject,
        DocumentTitle = mergeBody.MergeSettings.DocumentTitle,
        LastModificationDate = (DateTime)mergeBody.MergeSettings.LastModificationDate,
        UserPassword = mergeBody.MergeSettings.UserPassword
      };

      byte[] results = null;

      // save the document as PDF
      tx.Save(out results, TXTextControl.BinaryStreamType.AdobePDF, saveSettings);

      // return the merged document as base64 string
      return Ok(Convert.ToBase64String(results));
    }
  }
}

First, we need to do some error handling by checking that there is a MergeBody object and that it has a template and data provided to it. If not, we return a 400 Bad Request response.

Then a ServerTextControl object is created and the template is loaded. The MailMerge class is initialized with the given settings and the merge process is started. The resulting document is saved as a PDF document with the given settings and returned as a base64-encoded string.

The MergeBody Class

The MergeBody class is a simple class that contains the template, data, and settings for the merge process. The following code snippet shows the MergeBody class, the MergeSettings class, and the DocumentSettings class.

using Microsoft.AspNetCore.Mvc;

namespace TXTextControl.DocumentProcessing.Models
{
  public class MergeBody
  {
    [BindProperty(Name = "mergeData")]
    public string MergeData { get; set; }

    [BindProperty(Name = "template")]
    public string Template { get; set; }

    [BindProperty(Name = "mergeSettings")]
    public MergeSettings MergeSettings { get; set; }
  }

  public class DocumentSettings
  {
    [BindProperty(Name = "author")]
    public string Author { get; set; }

    [BindProperty(Name = "creationDate")]
    public DateTime? CreationDate { get; set; }

    [BindProperty(Name = "creatorApplication")]
    public string CreatorApplication { get; set; }

    [BindProperty(Name = "documentSubject")]
    public string DocumentSubject { get; set; }

    [BindProperty(Name = "documentTitle")]
    public string DocumentTitle { get; set; }

    [BindProperty(Name = "lastModificationDate")]
    public DateTime? LastModificationDate { get; set; }

    [BindProperty(Name = "userPassword")]
    public string UserPassword { get; set; }
  }

  public class MergeSettings : DocumentSettings
  {
    [BindProperty(Name = "removeEmptyFields")]
    public bool? RemoveEmptyFields { get; set; }

    [BindProperty(Name = "removeEmptyBlocks")]
    public bool? RemoveEmptyBlocks { get; set; }

    [BindProperty(Name = "removeEmptyImages")]
    public bool? RemoveEmptyImages { get; set; }

    [BindProperty(Name = "removeTrailingWhitespace")]
    public bool? RemoveTrailingWhitespace { get; set; }

    [BindProperty(Name = "removeEmptyLines")]
    public bool? RemoveEmptyLines { get; set; }

    [BindProperty(Name = "formFieldMergeType")]
    public int? FormFieldMergeType { get; set; }

    [BindProperty(Name = "culture")]
    public string Culture { get; set; }

    [BindProperty(Name = "dataSourceCulture")]
    public string DataSourceCulture { get; set; }

    [BindProperty(Name = "mergeCulture")]
    public string MergeCulture { get; set; }
  }
}

Calling the Web API

Now that we have the Web API endpoint, we can call it from a client application. The following code snippet shows how to call the Web API endpoint using the HttpClient class:

textControl1.Save(out data, TXTextControl.BinaryStreamType.InternalUnicodeFormat);

var MergeBody = new TXTextControl.DocumentProcessing.Models.MergeBody()
{
  MergeData = JsonConvert.SerializeObject(customer),
  Template = Convert.ToBase64String(data),
  MergeSettings = new TXTextControl.DocumentProcessing.Models.MergeSettings()
  {
    Author = "John Doe",
    CreationDate = DateTime.Now,
    CreatorApplication = "TX Text Control",
    DocumentSubject = "Subject",
    DocumentTitle = "Title",
    LastModificationDate = DateTime.Now,
    UserPassword = "password",
    RemoveEmptyFields = true,
    RemoveEmptyBlocks = true,
    RemoveEmptyImages = true,
    RemoveTrailingWhitespace = true,
    RemoveEmptyLines = true,
    FormFieldMergeType = 1,
    Culture = "en-US",
    DataSourceCulture = "en-US",
    MergeCulture = "en-US"
  }
};
    
var client = new HttpClient();

// convert content to json with lower case properties
var content = new StringContent(JsonConvert.SerializeObject(MergeBody, new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }), Encoding.UTF8, "application/json");
var response = client.PostAsync("https://localhost:7241/Document/Merge", content).Result;

// get the response as a string
var responseString = response.Content.ReadAsStringAsync().Result;

The HttpClient class is used to send a POST request to the Web API endpoint with the JSON payload containing the template, data, and settings for the merge process. The response is read as a base64-encoded string and saved as a PDF file.

Let's take a look at the JSON payload that is sent to the Web API endpoint:

{
   "mergeData":"{\"FirstName\":\"John\",\"LastName\":\"Doe\"}",
   "template":"CAcBAA4AAAAAAAAAAAAXAAIAqwBGAGkAcgBzAHQATgBhAG0AZQC7AHQAZQB4AHQAQwBvAG4AdAByAG8AbAAxAAAANgIAAAMAAQABAAEAAAAAAAAAAgCfhwEAAQALAAAAAAAAQAEAkgcAAABQAQAMAAAAAAAAAABAAAAAAAAAAFABAAwADAAAAAAAAEAAAAAAAAAAUDj/AAAAAAAAkAEAAAAAAAACIkFyaWFsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQABABgAAAAAAAAAAAAAAAAAZAAgAg8AAAABbgQB3AgBSg0BuBEBJhYBlBoBAh8BcCMB3icBTCwBujABKDUBljkBBD4BAAAAAAAAAAAAFAAAAEYAaQByAHMAdABOAGEAbQBlAAAAAQAHAAAAAAAAACwAAABNAEUAUgBHAEUARgBJAEUATABEAAAARgBpAHIAcwB0AE4AYQBtAGUAAAAAAAAAAAAAAAAAAAAAAAAAAABBAHIAaQBhAGwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOQEAAABAAEACQYAAQAAAC4AAP//AAAAALcAAQAAAABAAAAAUAEAAgAJBAAAAAA8AABkAAAAAAEAAAAJBAAAAAAAAABkAAAAAAEAAAAJBAAAAAAAAABkAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAEAAQABABgAAAAAAAAAAAAAAAAAAAAAAAEAUwB5AG0AYgBvAGwAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIQBAAAwAAQA0C8AAOA9AACgBaAFoAWgBQAAAEAAAAAAAAAAAAEAAAABAA4AAAAAAAAAAAAkAQAAAQAAAAAAOP8AAAAAAACQAQAAAAAAAAIiQXJpYWwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQQByAGkAYQBsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAFAAAAAAAAAAAAAAAABkACACDwAAAAFuBAHcCAFKDQG4EQEmFgGUGgECHwFwIwHeJwFMLAG6MAEoNQGWOQEEPgEAAQAJBgABAAAALgAA//8AAAAAtwABAAAAAEAAAABQAAASAAAAAAAAAAAAAAAAAAAAAAAAAAAACQRkAAAAWwBOAG8AcgBtAGEAbABdAAAAUwB5AG0AYgBvAGwAAAAAAABAIAABAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQB6AAAAMgAAAABAAAAAADcCNwI3AjcC0C8AAOA9AACgBaAFoAWgBSAKP4AAAAAAAAAAAAEAAAAAAAAAGwEAAAAAAAAAAAAAAAAAAAAAAAAsAAAAAAAAAAAAxgHGAcYBxgEAAABAAAAAQAAAAEAAAABAAAAAAAAAAAAAAA==",
   "mergeSettings":{
      "removeEmptyFields":true,
      "removeEmptyBlocks":true,
      "removeEmptyImages":true,
      "removeTrailingWhitespace":true,
      "removeEmptyLines":true,
      "formFieldMergeType":1,
      "culture":"en-US",
      "dataSourceCulture":"en-US",
      "mergeCulture":"en-US",
      "author":"John Doe",
      "creationDate":"2024-07-12T14:44:27.7222043+02:00",
      "creatorApplication":"TX Text Control",
      "documentSubject":"Subject",
      "documentTitle":"Title",
      "lastModificationDate":"2024-07-12T14:44:27.7244266+02:00",
      "userPassword":"password"
   }
}

Considerations

When designing a Web API for document generation, there are a few things to consider:

  • Security
    Ensure that authentication and authorization mechanisms are in place to secure the Web API endpoint.
  • Validation
    Prevent injection attacks and other security vulnerabilities by validating input data.
  • Performance
    To improve the responsiveness of the Web API, consider using a queuing system to offload the document generation process to a background task.
  • Scalability
    Use distributed architecture and load balancing to make the Web API scalable.
  • Monitoring
    Monitor the Web API for performance and availability using tools such as Application Insights.

Performance Considerations

Performance is an important consideration when generating large documents on the server side. You may want to consider using a queueing system to offload the document generation process to a background task to improve the responsiveness of the Web API. Depending on template size and data structure, document generation can be a complex, time-consuming task.

When generating documents with many nested merge blocks and 100s or 1000s of pages, this task can take several seconds or even minutes. A typical HTTP request should be returned within milliseconds with no significant delay. We have published a sample that shows how to queue requests and implement a REST web API that calls a web hook after the document has been successfully generated.

Learn More

Depending on the template size and data structure, generating documents can be a complex, time-consuming task. This sample shows how to build an asynchronous, RESTful Web API that calls a WebHook after the document generation process is terminated.

Generating Documents using a RESTful, Asynchronous Web API using WebHooks

Conclusion

In this article, we have seen how to design a Web API for document generation using the MailMerge class. We have also seen how to call the Web API from a client application and some considerations to keep in mind when designing a Web API for document generation.

By following these best practices, you can create a robust and scalable Web API for document generation that meets the needs of your application.

Download the sample project from our GitHub repository and try it out for yourself!

Stay in the loop!

Subscribe to the newsletter to receive the latest updates.

GitHub

Download and Fork This Sample on GitHub

We proudly host our sample code on github.com/TextControl.

Please fork and contribute.

Download ZIP

Open on GitHub

Open in Visual Studio

Requirements for this sample

  • TX Text Control .NET Server
  • Visual Studio 2022

Related Posts

ASP.NETASP.NET CoreDOCX

Use MailMerge in .NET on Linux to Generate Pixel-Perfect PDFs from DOCX…

This article explores how to use the TX Text Control MailMerge feature in .NET applications on Linux to generate pixel-perfect PDFs from DOCX templates. This powerful combination enables…


ASP.NETASP.NET CoreContract

Generating Dynamic NDAs Using TX Text Control MailMerge in C# .NET

This article demonstrates how to generate dynamic NDAs using TX Text Control MailMerge in C# .NET. It covers the process of creating a template, binding data, and generating the final document.


ASP.NETASP.NET CoreBackend

Designing a Maintainable PDF Generation Web API in ASP.NET Core (Linux) C#…

This article shows how to create a PDF generation Web API in ASP.NET Core on Linux using TX Text Control .NET Server. The clean architecture is used to create a maintainable and testable solution.


ASP.NETASP.NET CoreMailMerge

Manipulating Table Cells During the MailMerge Process in .NET C#

This article shows how to manipulate table cells during the mail merge process in .NET C#. The FieldMerged event can be used to manipulate the table cells after they are merged.


ASP.NETASP.NET CoreMailMerge

When to Generate Documents Server-Side Instead of Client-Side: A Focus on…

When it comes to document generation, deciding whether to handle the task server-side or client-side is a key architectural decision for any organization. This article discusses the benefits of…