# Store and Merge Templates in a Database using LiteDB and ASP.NET Core C#

> Editing the template, storing it in a database, and then merging it is a typical workflow for TX Text Control. This example will show you how to create a new template and how to store it in a LiteDB database. The template is then loaded from the database and merged with data.

- **Author:** Bjoern Meyer
- **Published:** 2023-11-23
- **Modified:** 2025-11-16
- **Description:** Editing the template, storing it in a database, and then merging it is a typical workflow for TX Text Control. This example will show you how to create a new template and how to store it in a LiteDB database. The template is then loaded from the database and merged with data.
- **5 min read** (876 words)
- **Tags:**
  - ASP.NET
  - Document Storage
  - MailMerge
  - Database
- **Web URL:** https://www.textcontrol.com/blog/2023/11/23/store-and-merge-templates-in-a-database-using-litedb-and-aspnet-core-csharp/
- **LLMs URL:** https://www.textcontrol.com/blog/2023/11/23/store-and-merge-templates-in-a-database-using-litedb-and-aspnet-core-csharp/llms.txt
- **LLMs-Full URL:** https://www.textcontrol.com/blog/2023/11/23/store-and-merge-templates-in-a-database-using-litedb-and-aspnet-core-csharp/llms-full.txt
- **GitHub Repository:** https://github.com/TextControl/TextControl.DocumentStorage

---

A very typical application for the variety of components that are part of TX Text Control is the visual creation of templates that are stored in a database. Documents in formats such as PDF are created by merging data into the stored templates.

To store the templates, this sample application uses a file-based database called [LiteDB](https://www.litedb.org/). The templates are created using the Document Editor visual component, and the templates are finally merged using the MailMerge class.

### Template Overview

When you start the application, you will see an overview of all the templates you have created.

![Creating documents with TX Text Control](https://s1-www.textcontrol.com/assets/dist/blog/2023/11/23/a/assets/step1.webp "Creating documents with TX Text Control")

### Data Excerpt Files

When you create a new template, the Document Editor is opened and dummy JSON data is generated to fill in the drop-down lists that contain the names of the fields that can be used.

![Creating documents with TX Text Control](https://s1-www.textcontrol.com/assets/dist/blog/2023/11/23/a/assets/step2.webp "Creating documents with TX Text Control")

A simple invoice structure is used as the data source.

```
public class Invoice
{
	public string InvoiceID { get; set; }
	public Customer Customer { get; set; }
	public string InvoiceNumber { get; set; }
	public string InvoiceDate { get; set; }

	public List<LineItem> LineItems { get; set; }
}

public class LineItem
{
	public string LineItemID { get; set; }
	public string Description { get; set; }
	public string Quantity { get; set; }
	public string Price { get; set; }
	public string Tax { get; set; }
	public string Total { get; set; }
}

public class Customer
{
	public string CustomerID { get; set; }
	public string Name { get; set; }
	public string Email { get; set; }
	public string Phone { get; set; }

	public string Address { get; set; }
	public string City { get; set; }
	public string State { get; set; }

	public string Zip { get; set; }
	public string Country { get; set; }
}
```

The *GetDummyInvoiceData* method generates a dummy JSON file from the data structure, which is then used in the Document Editor.

```
public static string GetDummyInvoiceData()
{
	Invoice invoice = new Invoice
	{
		InvoiceID = "123456789",
		InvoiceNumber = "123456789",
		InvoiceDate = "2020-01-01",
		Customer = new Customer
		{
			CustomerID = "123456789",
			Name = "John Doe",
			Email = ""
		},
		LineItems = new List<LineItem>
		{
			new LineItem
			{
				LineItemID = "123456789",
				Description = "Item 1",
				Quantity = "1",
				Price = "100.00",
				Tax = "10.00",
				Total = "110.00"
			},
			new LineItem
			{
				LineItemID = "123456789",
				Description = "Item 2",
				Quantity = "1",
				Price = "100.00",
				Tax = "10.00",
				Total = "110.00"
			},
			new LineItem
			{
				LineItemID = "123456789",
				Description = "Item 3",
				Quantity = "1",
				Price = "100.00",
				Tax = "10.00",
				Total = "110.00"
			}
		}
	};

	List<Invoice> invoices = new List<Invoice>();
	invoices.Add(invoice);

	return JsonConvert.SerializeObject(invoices);
}
```

### Creating the Editor

In the controller method *Editor*, the dummy data is created, and if an existing template is to be opened, the template is retrieved from the database.

```
public IActionResult Editor(string id = null)
{
    EditorViewModel model = new EditorViewModel()
    {
        InvoiceData = InvoiceData.GetDummyInvoiceData(),
        DocumentId = id
    };

    if (id != null)
    {
        // url encoded
        id = id.Replace("%2F", "/");

        model.TemplateData = Storage.GetTemplate(id);
    }

	return View(model);
}
```

In the view itself, the data and template are loaded into a Document Editor instance.

```
@{
    if (Model.TemplateData != null)
    {
        @Html.TXTextControl().TextControl().LoadDataFromJson(Model.InvoiceData).LoadText(Convert.FromBase64String(Model.TemplateData), TXTextControl.Web.BinaryStreamType.InternalUnicodeFormat).Render()
    }
    else
    {
        @Html.TXTextControl().TextControl().LoadDataFromJson(Model.InvoiceData).Render()
    }
}
```

### Template Storage

Once the template with merge fields and repeating blocks is created, the template can be saved using the *Save* button.

![Creating documents with TX Text Control](https://s1-www.textcontrol.com/assets/dist/blog/2023/11/23/a/assets/step3.webp "Creating documents with TX Text Control")

The *saveDocument* JavaScript function saves the document and posts it to the *Home/Save* endpoint along with the document ID.

```
function saveDocument() {
    TXTextControl.saveDocument(TXTextControl.StreamType.InternalUnicodeFormat, function (content) {
        $.ajax({
            type: "POST",
            url: "/Home/Save?id=@Model.DocumentId",
            contentType: "application/json",
            data: JSON.stringify(content),
            success: function () {
                setDirtyFlag();
                $("#save").addClass("disabled");
            },
            error: function () {
                alert("An error occurred while saving the data.");
            }
        });
    });
}
```

The endpoint calls the Storage.AddTemplate method with the document data and ID.

```
[HttpPost]
public IActionResult Save([FromBody] Content data, string id)
{
    Storage.AddTemplate(new MemoryStream(Convert.FromBase64String(data.Data)), id);
    return Ok();
}
```

This method uses LiteDB to store the file in the database with the unique identifier.

```
private static readonly LiteDatabase db = new LiteDatabase(@"Filename=App_Data/documents.db; Connection=shared");

 public static void AddTemplate(MemoryStream stream, string id = null, string name = "template.tx")
 {
     var templateId = id ?? "$/templates/" + Guid.NewGuid().ToString();

     db.FileStorage.Upload(templateId, name, stream);
 }
```

### Mail Merge

When you click *Merge*, the template is retrieved from the database and merged with the invoice data.

![Creating documents with TX Text Control](https://s1-www.textcontrol.com/assets/dist/blog/2023/11/23/a/assets/step4.webp "Creating documents with TX Text Control")

A PDF is created and downloaded directly.

![Creating documents with TX Text Control](https://s1-www.textcontrol.com/assets/dist/blog/2023/11/23/a/assets/step5.webp "Creating documents with TX Text Control")

The *Merge* method retrieves the template from the database by the given ID and uses MailMerge to merge the invoice data into the template.

```
public IActionResult Merge(string id)
{
    // url encoded
    id = id.Replace("%2F", "/");

    var templateData = Storage.GetTemplate(id);

    using (TXTextControl.ServerTextControl tx = new TXTextControl.ServerTextControl())
    {
        tx.Create();
        tx.Load(Convert.FromBase64String(templateData), TXTextControl.BinaryStreamType.InternalUnicodeFormat);
        
        using (MailMerge mailMerge = new MailMerge())
        {
            mailMerge.TextComponent = tx;
            mailMerge.MergeJsonData(InvoiceData.GetDummyInvoiceData());
        }
        
        tx.Save(out byte[] data, TXTextControl.BinaryStreamType.AdobePDF);

        // return pdf document
        return File(data, "application/pdf", "document.pdf");
    }
}
```

To see how the database interface works to store templates and merge data into them to generate PDF documents, you can download the full sources of this sample.

---

## About Bjoern Meyer

As CEO, Bjoern is the visionary behind our strategic direction and business development, bridging the gap between our customers and engineering teams. His deep passion for coding and web technologies drives the creation of innovative products. If you're at a tech conference, be sure to stop by our booth - you'll most likely meet Bjoern in person. With an advanced graduate degree (Dipl. Inf.) in Computer Science, specializing in AI, from the University of Bremen, Bjoern brings significant expertise to his role. In his spare time, Bjoern enjoys running, paragliding, mountain biking, and playing the piano.

- [LinkedIn](https://www.linkedin.com/in/bjoernmeyer/)
- [X](https://x.com/txbjoern)
- [GitHub](https://github.com/bjoerntx)

---

## Related Posts

- [Create SignFabric Envelopes from Mail Merge Templates in .NET C#](https://www.textcontrol.com/blog/2026/06/23/create-signfabric-envelopes-from-mail-merge-templates-using-dotnet-csharp/llms.txt)
- [Use MailMerge in .NET on Linux to Generate Pixel-Perfect PDFs from DOCX Templates](https://www.textcontrol.com/blog/2025/05/27/use-mailmerge-in-dotnet-on-linux-to-generate-pixel-perfect-pdfs-from-docx-templates/llms.txt)
- [Generating Dynamic NDAs Using TX Text Control MailMerge in C# .NET](https://www.textcontrol.com/blog/2025/04/08/generating-dynamic-ndas-using-tx-text-control-mailmerge-in-csharp-dotnet/llms.txt)
- [Designing a Maintainable PDF Generation Web API in ASP.NET Core (Linux) C# with Clean Architecture and TX Text Control](https://www.textcontrol.com/blog/2025/03/27/designing-a-maintainable-pdf-generation-web-api-in-asp-net-core-linux-c-sharp-with-clean-architecture-and-tx-text-control/llms.txt)
- [Getting Started: ServerTextControl and MailMerge in a .NET 8 Console Application on Linux with Docker and WSL](https://www.textcontrol.com/blog/2025/03/12/getting-started-servertextcontrol-and-mailmerge-in-a-net-8-console-application-on-linux-with-docker-and-wsl/llms.txt)
- [Manipulating Table Cells During the MailMerge Process in .NET C#](https://www.textcontrol.com/blog/2024/12/03/manipulating-table-cells-during-the-mailmerge-process-in-net-csharp/llms.txt)
- [When to Generate Documents Server-Side Instead of Client-Side: A Focus on Data Security](https://www.textcontrol.com/blog/2024/10/04/when-to-generate-documents-server-side-instead-of-client-side-a-focus-on-data-security/llms.txt)
- [Mail Merge: Inserting Merge Blocks using the DataSourceManager in C#](https://www.textcontrol.com/blog/2024/10/02/mail-merge-inserting-merge-blocks-using-the-datasourcemanager-in-csharp/llms.txt)
- [Creating Advanced Tables in PDF and DOCX Documents with C#](https://www.textcontrol.com/blog/2024/09/30/creating-advanced-tables-in-pdf-and-docx-documents-with-csharp/llms.txt)
- [Designing the Perfect Contract Template for MailMerge in C#](https://www.textcontrol.com/blog/2024/09/26/designing-the-perfect-contract-template-for-mailmerge-in-csharp/llms.txt)
- [Video Tutorial: Creating a MailMerge Template and JSON Data Structure](https://www.textcontrol.com/blog/2024/08/16/video-tutorial-creating-a-mailmerge-template-and-json-data-structure/llms.txt)
- [Getting Started Video Tutorial: How to use the MailMerge and ServerTextControl Classes in ASP.NET Core C#](https://www.textcontrol.com/blog/2024/08/05/getting-started-video-tutorial-how-to-use-the-mailmerge-and-servertextcontrol-classes-in-asp-net-core-c/llms.txt)
- [Getting Started Videos: New Text Control YouTube Channel](https://www.textcontrol.com/blog/2024/08/02/getting-started-videos-new-text-control-youtube-channel/llms.txt)
- [Best Practices for Mail Merge and Form Field Processing in ASP.NET Core C# Applications](https://www.textcontrol.com/blog/2024/07/30/best-practices-for-mail-merge-and-form-field-processing-in-asp-net-core-csharp-applications/llms.txt)
- [Advantages of Flow Type Layout Reporting vs. Banded Reporting or PDF Template Engines in .NET C#](https://www.textcontrol.com/blog/2024/07/29/advantages-of-flow-type-layout-reporting-vs-banded-reporting-or-pdf-template-engines-in-net-c-sharp/llms.txt)
- [Designing a MailMerge Web API Endpoint with ASP.NET Core in C#](https://www.textcontrol.com/blog/2024/07/12/designing-a-mailmerge-web-api-endpoint-with-asp-net-core-in-c-sharp/llms.txt)
- [Enhancing Documents with QR Codes and Barcodes in .NET C#: A Comprehensive Guide](https://www.textcontrol.com/blog/2024/07/11/enhancing-documents-with-qr-codes-and-barcodes-in-net-csharp-a-comprehensive-guide/llms.txt)
- [Document Automation 101: Leveraging TX Text Control for Business Efficiency in .NET C# Applications](https://www.textcontrol.com/blog/2024/07/09/document-automation-101-leveraging-tx-text-control-for-business-efficiency-in-net-c-applications/llms.txt)
- [Mail Merge: The Pre-Shaped Data Concept Explained](https://www.textcontrol.com/blog/2024/05/30/mail-merge-the-pre-shaped-data-concept-explained/llms.txt)
- [Creating Valid XRechnung / ZUGFeRD Invoices with ASP.NET Core C#](https://www.textcontrol.com/blog/2023/12/28/creating-valid-xrechnung-zugferd-invoices-with-asp-net-core-csharp/llms.txt)
- [Merging Templates with MailMerge with Different Merge Field Settings in C#](https://www.textcontrol.com/blog/2023/12/16/merging-templates-with-mailmerge-with-different-merge-field-settings/llms.txt)
- [How to Mail Merge MS Word DOCX Documents in ASP.NET Core C#](https://www.textcontrol.com/blog/2023/10/16/how-to-mail-merge-ms-word-docx-documents-in-aspnet-core-csharp/llms.txt)
- [Mail Merge: Conditional Data Shaping in Merge Blocks](https://www.textcontrol.com/blog/2023/05/03/mail-merge-conditional-data-shaping-in-merge-blocks/llms.txt)
- [Use Case: Blood Pressure Report with Charts in C#](https://www.textcontrol.com/blog/2023/04/27/use-case-blood-pressure-report-with-charts-in-csharp/llms.txt)
- [MailMerge Class Performance Benchmark](https://www.textcontrol.com/blog/2023/04/21/mailmerge-performance-benchmark/llms.txt)
