TX Text Control .NET Server

Loading and Saving Documents

Topic

With the editor added to an application, as in ASP.NET Core in Getting Started, the next step is to open and store real documents. They get into the Document Editor when the view is rendered or from JavaScript while the editor is open, and back to your server through an ASP.NET Core controller that stores them.

The examples extend the ASP.NET Core MVC application of that tutorial. The same JavaScript calls work in the Angular, React and JavaScript frontends.

How Loading and Saving Works

While a document is open in the editor, it exists in the editing session on the server, not as a file. You decide where it comes from and where it goes:

  • When the view is rendered, your Razor view passes a document to the editor with LoadText. The document can be a file on the server, a byte array or a string.
  • While the editor is open, JavaScript in the browser replaces the document with loadDocument and gets the current document with saveDocument. Both exchange the document as data, which your code sends to or receives from your server.
  • In Blazor, your C# code calls LoadDocumentAsync and SaveDocumentAsync of the component instead; see Blazor in Getting Started.

The editor has no storage of its own. Nothing is saved until your code saves it.

Load a Document When the View Is Rendered

LoadText replaces the content of the editor before the view is sent to the browser. It has one overload for each kind of source:

OverloadLoads
LoadText(string path, StreamType)A file on the server
LoadText(System.IO.FileStream, StreamType)A stream, from its current position
LoadText(byte[] data, BinaryStreamType)A document in a byte array, for example from a database
LoadText(string data, StringStreamType)A document in a string, for example HTML

The format parameters are the StreamType, BinaryStreamType and StringStreamType enumerations of the TXTextControl.Web namespace. The tutorial already loads a file and an HTML string. To load a document that your controller reads, for example from a database, pass it as a byte array. In Controllers/HomeController.cs, read the document in the Index action:

public IActionResult Index()
{
    // Read the document, for example from a database or a file
    ViewBag.Document = System.IO.File.ReadAllBytes("Documents/template.docx");

    return View();
}

Then pass the byte array to LoadText in Views/Home/Index.cshtml:

@using TXTextControl.Web.MVC

@Html.TXTextControl().TextControl().LoadText(
    (byte[])ViewBag.Document,
    TXTextControl.Web.BinaryStreamType.WordprocessingML).Render()

WordprocessingML is the DOCX format. When the page opens, the editor shows the document.

Load a Document From JavaScript

TXTextControl.loadDocument replaces the document in the editor while it is open. It takes the format, the document as a base64-encoded string, and a callback that is called when loading is finished:

function loadHtml() {
  var html = "<p>Dear customer,</p><p>thank you for your order.</p>";

  TXTextControl.loadDocument(
    TXTextControl.StreamType.HTMLFormat,
    TXTextControl.btoaUTF8(html),
    function (result) {
      console.log(result.bytesRead + " bytes loaded");
    });
}

An optional fourth parameter takes a LoadSettings object with settings such as the password of a protected document (userPassword) or whether images are loaded (loadImages). The optional fifth parameter is an error callback.

Call loadDocument only after the editor has raised the textControlLoaded event, for example from a button or inside a handler of this event. After a document has been loaded, the editor raises the documentLoaded event; see Events.

Save a Document From JavaScript

TXTextControl.saveDocument saves the current document in a format and passes the result to a callback:

function saveAsDocx() {
  TXTextControl.saveDocument(TXTextControl.StreamType.WordprocessingML, function (result) {
    console.log(result.bytesWritten + " bytes written");
  });
}

The callback receives a SaveDocumentResult. Its data property depends on the format:

Formatdata contains
Binary formats such as DOCX, PDF and the TX Text Control formatThe document as a base64-encoded string
Text formats such as HTML and RTFThe document as plain text

Keep this in mind when you send the result to your server: decode base64 only for binary formats. An optional third parameter takes a SaveSettings object with settings such as the document title (documentTitle) or a password for a PDF document (userPassword).

Store Documents on the Server

In most applications, users open a stored document, edit it and save it back. The following example stores DOCX documents in the Documents folder of the project. A controller receives the documents that saveDocument creates and returns documents for loadDocument.

Add the Controller

Create Controllers/DocumentController.cs with the following code:

using Microsoft.AspNetCore.Mvc;

public class DocumentController : Controller
{
    // Return a document from the Documents folder as base64-encoded data
    [HttpGet]
    public DocumentData Load(string name)
    {
        var file = Path.Combine("Documents", Path.GetFileName(name));

        return new DocumentData
        {
            Name = name,
            Data = Convert.ToBase64String(System.IO.File.ReadAllBytes(file))
        };
    }

    // Store a document that saveDocument created in a binary format
    [HttpPost]
    public bool Save([FromBody] DocumentData documentData)
    {
        var file = Path.Combine("Documents", Path.GetFileName(documentData.Name));
        System.IO.File.WriteAllBytes(file, Convert.FromBase64String(documentData.Data));

        return true;
    }
}

public class DocumentData
{
    public string Name { get; set; } = string.Empty;
    public string Data { get; set; } = string.Empty;
}

The code works as follows:

  • Load reads a file and returns it as a JSON object with the name and the base64-encoded data.
  • Save receives the same JSON object in the body of a POST request, decodes the data and writes the file.
  • Path.GetFileName keeps only the file name of the name the browser sends, so that a request can't write outside the Documents folder.

The controller expects binary data. To store HTML or RTF, which saveDocument returns as plain text, write the text instead of decoding it.

Add the Buttons

Replace the content of Views/Home/Index.cshtml with the following code:

@using TXTextControl.Web.MVC

@Html.TXTextControl().TextControl().LoadText(
    "Documents/template.docx",
    TXTextControl.Web.StreamType.WordprocessingML).Render()

<input type="button" onclick="saveToServer()" value="Save Document" />
<input type="button" onclick="loadFromServer()" value="Load Document" />

<script>
    function saveToServer() {
        TXTextControl.saveDocument(TXTextControl.StreamType.WordprocessingML, function (result) {
            fetch("/Document/Save", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ name: "output.docx", data: result.data })
            });
        });
    }

    function loadFromServer() {
        fetch("/Document/Load?name=output.docx")
            .then(response => response.json())
            .then(stored => {
                TXTextControl.loadDocument(
                    TXTextControl.StreamType.WordprocessingML,
                    stored.data,
                    function (result) {
                        console.log(result.bytesRead + " bytes loaded");
                    });
            });
    }
</script>

What the page does:

  • LoadText opens Documents/template.docx when the page is rendered, as in the tutorial.
  • saveToServer saves the document as DOCX and posts the base64-encoded data to the Save action.
  • loadFromServer requests output.docx from the Load action and passes the data to loadDocument.

Run the application, change the document and click Save Document. The project's Documents folder now contains output.docx. Change the document again and click Load Document to return to the saved version.

Append a Document

TXTextControl.append adds a document to the end of the current document instead of replacing it:

function appendParagraph() {
  TXTextControl.append(
    TXTextControl.StreamType.HTMLFormat,
    TXTextControl.btoaUTF8("<p>Appended text</p>"),
    function (result) {
      console.log(result.bytesRead + " bytes appended");
    },
    null,
    TXTextControl.AppendSettings.StartWithNewParagraph);
}

The fourth parameter is a LoadSettings object, which can be null. The fifth is a value of AppendSettings: None inserts the text at the end of the last paragraph, StartWithNewParagraph in a new paragraph and StartWithNewSection in a new section.

Angular and React

The Angular and React components have no property that loads a document. Load and save with the same JavaScript API once the editor is ready: in Angular, in a handler of the txDocumentEditorLoaded event, and in React, in the function of the onLoad property. Angular and React in Getting Started show where this code goes.

Formats

The JavaScript StreamType enumeration contains the formats WordprocessingML (DOCX), RichTextFormat (RTF), HTMLFormat, PlainText, InternalUnicodeFormat (the TX Text Control format), AdobePDF, SpreadsheetML (XLSX) and MSWord (DOC).

The Document Editor backend uses the Core engine, which doesn't load or save DOC documents. RTF is supported by the Core engine since version 34.0. Supported File Formats lists the formats and their limitations.

Next Steps