Word Editor in ASP.NET MVC

GemBox.Document is a standalone .NET component that's ideal for web applications (like ASP.NET MVC, ASP.NET Core and ASP.NET Web Forms) because of its fast performance and thread safety when working with multiple DocumentModel objects.

GemBox.Document supports reading and writing documents from or to Stream, so you can easily load a document that's uploaded to server and save the resulting document to browser by downloading it.

Also, GemBox.Document supports both reading and writing HTML content, which enables you to combine it with any WYSIWYG HTML editor in order to create an advanced online Word editor, one that's capable of saving to PDF, combining multiple documents, executing a mail merge process and a lot more.

The following example demonstrates interoperability between GemBox.Document library and TinyMCE control from an ASP.NET MVC application. Note, you can use the same approach with any rich text editor like CKEditor, Quill, etc.

Screenshot of rich text editor for Word files in ASP.NET MVC
Word editor that combines WYSIWYG HTML editor and GemBox.Document in ASP.NET MVC demo application
Screenshot of downloaded PDF file in ASP.NET MVC
Generated and downloaded PDF document from template Word document in ASP.NET MVC demo application
@model AspNetWordEditor.FileModel

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Word Editor in ASP.NET MVC</title>
    <script src="~/Scripts/TinyMCE/tinymce.min.js"></script>
    <script type="text/javascript">
        tinyMCE.init({
            selector: "textarea#file-editor",
            height: 400,
            setup: (editor) => editor.on('init', () =>
                editor.setContent("<p>Welcome to ASP.NET MVC demo that uses <strong>GemBox.Document</strong> library and <strong>TinyMCE</strong> editor.</p>")),
        });
    </script>
    <style>
        body {
            font-family: Calibri;
            color: #514E52;
        }

        form { max-width: 800px; }

        #file-generator * {
            padding: 10px;
            margin: 10px
        }
    </style>
</head>
<body>
    @using (Html.BeginForm("Download", "Home"))
    {
        @Html.AntiForgeryToken()

        @Html.TextAreaFor(model => model.Content, new { id = "file-editor" })

        <div id="file-generator">
            <input type="submit" value="Download" />
            as
            @Html.DropDownListFor(model => model.Extension,
                new[]
                {
                    new SelectListItem() { Text = "DOCX", Value = ".docx" },
                    new SelectListItem() { Text = "PDF", Value = ".pdf", Selected = true },
                    new SelectListItem() { Text = "XPS", Value = ".xps" },
                    new SelectListItem() { Text = "HTML", Value = ".html" },
                    new SelectListItem() { Text = "MHTML", Value = ".mhtml" },
                    new SelectListItem() { Text = "RTF", Value = ".rtf" },
                    new SelectListItem() { Text = "XML", Value = ".xml" },
                    new SelectListItem() { Text = "TXT", Value = ".txt" },
                    new SelectListItem() { Text = "PNG", Value = ".png" },
                    new SelectListItem() { Text = "JPEG", Value = ".jpeg" },
                    new SelectListItem() { Text = "GIF", Value = ".gif" },
                    new SelectListItem() { Text = "BMP", Value = ".bmp" },
                    new SelectListItem() { Text = "TIFF", Value = ".tiff" },
                    new SelectListItem() { Text = "WMP", Value = ".wmp" }
                })
        </div>
    }
</body>
</html>
using System.IO;
using System.Web.Mvc;
using GemBox.Document;

namespace AspNetWordEditor
{
    public class HomeController : Controller
    {
        [HttpGet]
        public ActionResult Index() => this.View();

        [HttpPost]
        public FileResult Download(FileModel model)
        {
            // If using Professional version, put your serial key below.
            ComponentInfo.SetLicense("FREE-LIMITED-KEY");

            var templateFile = Server.MapPath("~/App_Data/%#DocumentTemplate.docx%");

            // Load template document.
            var document = DocumentModel.Load(templateFile);

            // Insert content from HTML editor.
            var bookmark = document.Bookmarks["HtmlBookmark"];
            bookmark.GetContent(true).LoadText(model.Content, LoadOptions.HtmlDefault);

            // Save document to stream in specified format.
            var saveOptions = GetSaveOptions(model.Extension);
            var stream = new MemoryStream();
            document.Save(stream, saveOptions);

            // Download document.
            var downloadFile = $"Output{model.Extension}";
            return File(stream.ToArray(), saveOptions.ContentType, downloadFile);
        }

        private static SaveOptions GetSaveOptions(string extension)
        {
            switch (extension)
            {
                case ".docx": return SaveOptions.DocxDefault;
                case ".pdf": return SaveOptions.PdfDefault;
                case ".xps": return SaveOptions.XpsDefault;
                case ".html": return SaveOptions.HtmlDefault;
                case ".mhtml": return new HtmlSaveOptions() { HtmlType = HtmlType.Mhtml };
                case ".rtf": return SaveOptions.RtfDefault;
                case ".xml": return SaveOptions.XmlDefault;
                case ".png": return SaveOptions.ImageDefault;
                case ".jpeg": return new ImageSaveOptions(ImageSaveFormat.Jpeg);
                case ".gif": return new ImageSaveOptions(ImageSaveFormat.Gif);
                case ".bmp": return new ImageSaveOptions(ImageSaveFormat.Bmp);
                case ".tiff": return new ImageSaveOptions(ImageSaveFormat.Tiff);
                case ".wmp": return new ImageSaveOptions(ImageSaveFormat.Wmp);
                default: return SaveOptions.TxtDefault;
            }
        }
    }

    public sealed class FileModel
    {
        [AllowHtml]
        public string Content { get; set; }
        public string Extension { get; set; }
    }
}
Imports System.IO
Imports System.Web.Mvc
Imports GemBox.Document

Namespace AspNetWordEditor
    Public Class HomeController
        Inherits Controller

        <HttpGet>
        Function Index() As ActionResult
            Return View()
        End Function

        <HttpPost>
        Function Download(model As FileModel) As FileResult

            ' If using Professional version, put your serial key below.
            ComponentInfo.SetLicense("FREE-LIMITED-KEY")

            Dim templateFile = Server.MapPath("~/App_Data/%#DocumentTemplate.docx%")

            ' Load template document.
            Dim document = DocumentModel.Load(templateFile)

            ' Insert content from HTML editor.
            Dim bookmark = document.Bookmarks("HtmlBookmark")
            bookmark.GetContent(True).LoadText(model.Content, LoadOptions.HtmlDefault)

            ' Save document to stream in specified format.
            Dim saveOptions = GetSaveOptions(model.Extension)
            Dim stream As New MemoryStream()
            document.Save(stream, saveOptions)

            ' Download document.
            Dim downloadFile = $"Output{model.Extension}"
            Return File(stream.ToArray(), saveOptions.ContentType, downloadFile)

        End Function

        Private Shared Function GetSaveOptions(extension As String) As SaveOptions
            Select Case extension
                Case ".docx"
                    Return SaveOptions.DocxDefault
                Case ".pdf"
                    Return SaveOptions.PdfDefault
                Case ".xps"
                    Return SaveOptions.XpsDefault
                Case ".html"
                    Return SaveOptions.HtmlDefault
                Case ".mhtml"
                    Return New HtmlSaveOptions() With {.HtmlType = HtmlType.Mhtml}
                Case ".rtf"
                    Return SaveOptions.RtfDefault
                Case ".xml"
                    Return SaveOptions.XmlDefault
                Case ".png"
                    Return SaveOptions.ImageDefault
                Case ".jpeg"
                    Return New ImageSaveOptions(ImageSaveFormat.Jpeg)
                Case ".gif"
                    Return New ImageSaveOptions(ImageSaveFormat.Gif)
                Case ".bmp"
                    Return New ImageSaveOptions(ImageSaveFormat.Bmp)
                Case ".tiff"
                    Return New ImageSaveOptions(ImageSaveFormat.Tiff)
                Case ".wmp"
                    Return New ImageSaveOptions(ImageSaveFormat.Wmp)
                Case Else
                    Return SaveOptions.TxtDefault
            End Select
        End Function

    End Class

    Public NotInheritable Class FileModel
        <AllowHtml>
        Public Property Content As String
        Public Property Extension As String
    End Class
End Namespace

GemBox.Document is only licensed per developer and the licenses include a royalty-free deployment. There are no server or OEM licenses, there are no additional costs for anything (like building, testing and deploying).

So, you're free to build an unlimited number of applications and deploy or distribute them to an unlimited number of servers or end user machines with no extra cost.

Check next example or download examples from GitHub.