ASP.NET Core
A real ASP.NET Core application rarely looks like a tutorial project. It has its own controllers, services and authentication, and it often needs the Document Editor, the Document Viewer and server-side document processing at the same time. All three parts of TX Text Control .NET Server fit into one application, and the same application can serve as the backend for Angular, React and JavaScript frontends.
The first steps with a new project are in Document Editor: ASP.NET Core and Document Viewer: ASP.NET Core. Read on for the packages each part needs, Program.cs for MVC views, Razor Pages and a backend of separate frontends, controllers that exchange documents, the use of ServerTextControl in request handlers and the protection of the endpoints.
Choose the Packages
Install the packages of the parts your application uses from the Text Control Private NuGet Feed:
| Part | Packages | What they add |
|---|---|---|
| Document Editor | TXTextControl.Web, TXTextControl.Web.DocumentEditor.Backend | The HTML helper, the WebSocket middleware and the backend process with its hosted service |
| Document Viewer | TXTextControl.Web.DocumentViewer | The HTML helper and the TextControl controller that serves the pages |
| Document processing | none besides the engine | ServerTextControl and MailMerge |
| The engine, for every part | TXTextControl.TextControl.Core.SDK | The document engine |
The web packages contain no engine, so every application also installs an engine package. This guide uses the Core engine. The Classic engine, TXTextControl.TextControl.ASP.SDK, runs on Windows only and uses TXTextControl.Web.DocumentViewer.Classic for the viewer; the backend package of the Document Editor requires Core. Package Overview describes every package.
For an application with all parts, run in the project folder:
dotnet add package TXTextControl.TextControl.Core.SDK
dotnet add package TXTextControl.Web
dotnet add package TXTextControl.Web.DocumentEditor.Backend
dotnet add package TXTextControl.Web.DocumentViewer
Configure Program.cs for Views
In an MVC application, the editor and the viewer are added to views. Program.cs needs two additions for the Document Editor and none for the Document Viewer: the complete file is in Configure Program.cs of the Getting Started tutorial, and it serves both components unchanged. What matters when the application grows:
AddHostedService<DocumentEditorWorkerManager>()starts the backend processTXTextControl.Web.Server.Corewhen the application starts, forwards its output to the logging of your application and stops it when the application shuts down.UseWebSocketsandUseTXWebSocketMiddlewarego afterUseRoutingand before the endpoint mappings. A middleware that checks access tokens for the editor goes between the two calls; WebSocket Architecture explains the order and the overloads ofUseTXWebSocketMiddleware.UseAuthorizationafter the WebSocket middleware protects your pages, but not the WebSocket connection; Require Signed-In Users shows the order that protects both.- The Document Viewer needs no line: the controller route of the template also maps the
TextControlcontroller of the viewer package. Don't name a controller of your ownTextControl.
When the backend process needs another address or port, bind DocumentEditorWorkerOptions to a section of appsettings.json before AddHostedService and pass the same values to UseTXWebSocketMiddleware, as Configure the Backend Process describes.
Use Razor Pages
In a Razor Pages application, the HTML helpers work in .cshtml pages the same way as in MVC views. The Document Viewer needs its controller, which a Razor Pages application doesn't map by itself, so Program.cs registers the controllers and calls UseTXDocumentViewer:
using TXTextControl.Web;
using TXTextControl.Web.DocumentEditor.Backend;
using TXTextControl.Web.MVC.DocumentViewer;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllers();
builder.Services.AddHostedService<DocumentEditorWorkerManager>();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseWebSockets();
app.UseTXWebSocketMiddleware();
// Maps the controller of the viewer and runs the endpoints
app.UseTXDocumentViewer();
app.MapStaticAssets();
app.MapRazorPages()
.WithStaticAssets();
app.Run();
The code works as follows:
AddControllersregisters theTextControlcontroller of the viewer package, andUseTXDocumentViewermaps its route. Without both, the viewer page renders, but the requests of the viewer for its scripts return 404.MapControllersalone doesn't map the controller of the viewer.UseTXDocumentViewerruns the endpoints, including the Razor Pages, soUseAuthorizationcomes before it.- The editor needs the same two additions as in an MVC application: the hosted service and the WebSocket middleware.
A page shows the editor with @using TXTextControl.Web.MVC and @Html.TXTextControl().TextControl(), and the viewer with @using TXTextControl.Web.MVC.DocumentViewer and @Html.TXTextControl().DocumentViewer(), as in the views of the Getting Started tutorials.
Configure Program.cs for Separate Frontends
Angular, React and JavaScript frontends run as separate applications and call an ASP.NET Core backend without views, usually created from the ASP.NET Core Web API template. One backend serves the Document Editor, the Document Viewer and your own controllers:
using TXTextControl.Web;
using TXTextControl.Web.DocumentEditor.Backend;
using TXTextControl.Web.MVC.DocumentViewer;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddHostedService<DocumentEditorWorkerManager>();
// Allow the frontend's origin to call the viewer and your controllers
builder.Services.AddCors(options => options.AddPolicy("frontend", policy =>
{
policy.WithOrigins("http://localhost:4200").AllowAnyMethod().AllowAnyHeader();
}));
var app = builder.Build();
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors("frontend");
app.UseAuthorization();
// Document Editor
app.UseWebSockets();
app.UseTXWebSocketMiddleware();
// Document Viewer: runs the endpoints, so it comes after CORS and authorization
app.UseTXDocumentViewer();
app.MapControllers();
app.Run();
The code works as follows:
AddControllersregisters the controllers, including theTextControlcontroller of the viewer package.AddCorsandUseCorsallow requests from the origin of the frontend, here the Angular development server. The Document Viewer needs the policy because the viewer in the browser calls the backend with HTTP requests from another origin. The Document Editor needs no CORS policy. Replace the origin with the address of your frontend, for examplehttp://localhost:5173for a Vite development server.UseTXDocumentVieweradds the Document Viewer to a backend without MVC views. The README of the viewer package places it afterapp.UseRouting(). Middleware that has to apply to the requests of the viewer and of your controllers, such asUseCors,UseAuthentication,UseAuthorizationand a middleware that checks access tokens, goes before it.
The frontends connect to this backend with the WebSocket URL wss://<backend>/api/TXWebSocket for the editor and the base path https://<backend> for the viewer. Angular, React and JavaScript show the client side.
Add a Document Controller
Frontends load documents from the backend and send edited documents back. Use the DocumentController of Store Documents on the Server: it stores DOCX documents in the Documents folder of the project and exchanges them as JSON objects with a name and base64-encoded data, the form in which saveDocument returns binary formats and loadDocument accepts them.
A backend created from the ASP.NET Core Web API template maps controllers only with MapControllers and has no conventional route, so the controller needs attribute routes. Change the class and the two action attributes:
[]
[]
public class DocumentController : ControllerBase
{
[]
public DocumentData Load(string name) { /* as in the Document Editor section */ }
[]
public bool Save([FromBody] DocumentData documentData) { /* unchanged */ }
}
The actions then answer GET /Document/Load?name=... and POST /Document/Save, the URLs the Angular, React and JavaScript examples call.
Show the Editor and the Viewer in One View
A view can combine both components, for example to show a merged preview of the template a user edits. Both packages define an Html.TXTextControl() helper, so the view creates the editor with the helper and the viewer in code:
@using TXTextControl.Web.MVC
<input type="button" onclick="showPreview()" value="Preview" />
<div style="display: flex; gap: 1rem;">
<div style="width: 50%; height: 600px;">
@Html.TXTextControl().TextControl(settings => {
settings.Dock = TXTextControl.Web.DockStyle.Fill;
}).LoadText("Documents/template.docx", TXTextControl.Web.StreamType.WordprocessingML).Render()
</div>
<div style="width: 50%; height: 600px;">
@{
var viewerSettings = new TXTextControl.Web.MVC.DocumentViewer.DocumentViewerSettings();
viewerSettings.Dock = TXTextControl.Web.MVC.DocumentViewer.DocumentViewerSettings.DockStyle.Fill;
viewerSettings.ShowThumbnailPane = false;
var viewer = new TXTextControl.Web.MVC.DocumentViewer.DocumentViewer(viewerSettings);
@viewer.Render()
}
</div>
</div>
<script>
function showPreview() {
TXTextControl.saveDocument(TXTextControl.StreamType.InternalUnicodeFormat, function (result) {
fetch("/MailMerge/Merge", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(result.data)
})
.then(response => response.text())
.then(merged => TXDocumentViewer.loadDocument(merged, "preview.tx"));
});
}
</script>
The controller merges the template with the data in Documents/data.json and returns the result:
using Microsoft.AspNetCore.Mvc;
using TXTextControl;
using TXTextControl.DocumentServer;
public class MailMergeController : Controller
{
[]
public IActionResult Merge([FromBody] string template)
{
using (ServerTextControl tx = new ServerTextControl())
{
tx.Create();
tx.Load(Convert.FromBase64String(template), BinaryStreamType.InternalUnicodeFormat);
using (MailMerge mailMerge = new MailMerge { TextComponent = tx })
{
mailMerge.MergeJsonData(System.IO.File.ReadAllText("Documents/data.json"));
}
tx.Save(out byte[] data, BinaryStreamType.InternalUnicodeFormat);
return Content(Convert.ToBase64String(data));
}
}
}
The code works as follows:
- TXTextControl.saveDocument saves the template in the internal format of TX Text Control and passes the base64-encoded data to the controller.
- The controller loads the template into a ServerTextControl, merges it with MailMerge.MergeJsonData and returns the merged document as base64 text.
- TXDocumentViewer.loadDocument shows the result under the name that its second parameter passes.
- DocumentViewer takes DocumentViewerSettings, and Render writes the viewer into the page.
The blog article ASP.NET Core: Use the Document Editor and Viewer in the Same Razor View updates the preview automatically while the user types.
Use ServerTextControl in Request Handlers
Controllers and services create documents with ServerTextControl and MailMerge in the process of your application. Keep the following in mind:
- One instance per operation. Create a
ServerTextControlfor each request or task in ausingblock, as Create One Instance per Operation describes. - A service for document logic. Put the document code into a service class that a controller receives through dependency injection. The service stays testable and reusable in other controllers.
- Class libraries. When the document code lives in a class library that other assemblies call, set ServerTextControl.EntryAssembly, as License File Changes describes.
The following service converts DOCX documents to PDF:
using TXTextControl;
public interface IPdfService
{
byte[] ConvertToPdf(byte[] docx);
}
public class PdfService : IPdfService
{
public byte[] ConvertToPdf(byte[] docx)
{
using (ServerTextControl tx = new ServerTextControl())
{
tx.Create();
tx.Load(docx, BinaryStreamType.WordprocessingML);
tx.Save(out byte[] pdf, BinaryStreamType.AdobePDF);
return pdf;
}
}
}
Register it in Program.cs before builder.Build() with builder.Services.AddScoped<IPdfService, PdfService>();. A controller receives it in its constructor:
using Microsoft.AspNetCore.Mvc;
[]
[]
public class PdfController : ControllerBase
{
private readonly IPdfService _pdfService;
public PdfController(IPdfService pdfService)
{
_pdfService = pdfService;
}
[]
public IActionResult Template()
{
byte[] pdf = _pdfService.ConvertToPdf(System.IO.File.ReadAllBytes("Documents/template.docx"));
return File(pdf, "application/pdf", "template.pdf");
}
}
REST Services goes further with endpoints that other applications call.
Separate Editing and Processing Under Load
With many concurrent users, heavy document processing in the application that hosts the WebSocket connections of the editors can block these connections. Separate Processing From Editing and Scaling Beyond One Instance describe the recommended split.
Protect the Endpoints
The endpoints of the editor and the viewer are part of your application and need the same protection as the rest of it:
- Document Editor. A middleware between
UseWebSocketsandUseTXWebSocketMiddlewarechecks a token before the WebSocket connection is established. See WebSocket Security. - Document Viewer. A middleware before
UseTXDocumentViewerchecks the token that the view passes in the base path. See Protect the Endpoints in the Document Viewer section. - Your controllers. Document endpoints read and write files and create documents; Authentication covers how to protect them.
When users sign in to your application, for example with cookie authentication, a fallback policy protects the editor, the viewer and your controllers without tokens, provided UseAuthentication and UseAuthorization come before the TX Text Control middleware. Require Signed-In Users shows the code and the order.
Applications on the .NET Framework
ASP.NET MVC and Web Forms applications on the .NET Framework use the Classic engine and a different setup of the Document Editor. ASP.NET on .NET Framework has the tutorials for these applications. To move such an application to ASP.NET Core and the NuGet packages, follow From ASP.NET MVC on the .NET Framework to ASP.NET Core.
Next Steps
- WebSocket Architecture: the connection of the Document Editor in detail.
- REST Services: build document endpoints that other applications call.
- Angular: connect an Angular application to the backend.
- Deployment Guide: publish the application to Windows, Linux, Docker and Azure.