Skip to main content

Dockerize an Office File API Application

  • 5 minutes to read

This tutorial describes how to create and dockerize an ASP.NET Core Web API application that uses the Office File API library to convert Excel and Word documents to HTML.

View Example: Dockerize an Office File API Application

Prerequisites

Create an Application

  1. Create a folder for your project (DocumentConversionWebApi in this example) and open this folder in Visual Studio Code.

  2. Click ViewTerminal in the main menu to open the integrated terminal.

  3. Use the dotnet new command to create a new Web API application.

    dotnet new webapi -o DocumentConversionWebApi
    cd DocumentConversionWebApi
    

    The image below shows the created project’s structure.

    Office_WebApi_Project_Structure

    Note

    The ASP.NET Core Web API project template contains WeatherForecast API. Delete the files WeatherForecast.cs and Controllers/WeatherForecastController.cs to remove this API from your project.

  4. Install the DevExpress.Document.Processor NuGet package as described in this help topic: Use NuGet Packages to Install Office File API Components.

    Important

    You need a license for the DevExpress Office File API Subscription or DevExpress Universal Subscription to use this package in production code.

  5. Implement an API controller to handle HTTP requests. In the Controllers folder, create a ConvertFileController.cs file with the code below. Implement a PostConvertFile action method to handle HTTP POST requests and to convert uploaded files to HTML.

    using Microsoft.AspNetCore.Mvc;
    using DevExpress.Spreadsheet;
    using DevExpress.XtraRichEdit;
    using DevExpress.XtraSpreadsheet.Export;
    
    namespace DocumentConversionWebApi.Controllers {
        [Route("[controller]")]
        [ApiController]
        public class ConvertFileController : ControllerBase {
            [HttpGet]
            public ActionResult Index() {
                return Content("Index");
            }
            [HttpPost]
            public async Task<IActionResult> PostConvertFile(IFormFile file) {
                if (file != null) {
                    try {
                        using (var stream = new MemoryStream()) {
                            await file.CopyToAsync(stream);
                            stream.Seek(0, SeekOrigin.Begin);
                            switch (Path.GetExtension(file.FileName)) {
                                case ".rtf":
                                case ".doc":
                                case ".docx":
                                case ".txt":
                                case ".mht":
                                case ".odt":
                                case ".xml":
                                case ".epub":
                                case ".html":
                                    return new FileStreamResult(ConvertWordDocument(stream), "text/html");
                                case ".xlsx":
                                case ".xlsm":
                                case ".xlsb":
                                case ".xls":
                                case ".xltx":
                                case ".xltm":
                                case ".xlt":
                                case ".csv":
                                    return new FileStreamResult(ConvertSpreadsheetDocument(stream), "text/html");
                            }
                        }
                    } catch (Exception e) {
                        return StatusCode(500, e.Message + Environment.NewLine + e.StackTrace);
                    }
                }
                return new BadRequestResult();
            }
    
            Stream ConvertWordDocument(Stream inputStream) {
                using (var wordProcessor = new RichEditDocumentServer()) {
                    wordProcessor.LoadDocument(inputStream);
                    var resultStream = new MemoryStream();
                    wordProcessor.Options.Export.Html.EmbedImages = true;
                    wordProcessor.SaveDocument(resultStream, DevExpress.XtraRichEdit.DocumentFormat.Html);
                    resultStream.Seek(0, SeekOrigin.Begin);
                    return resultStream;
                }
            }
            Stream ConvertSpreadsheetDocument(Stream inputStream) {
                using (var workbook = new Workbook()) {
                    workbook.LoadDocument(inputStream);
                    var resultStream = new MemoryStream();
                    var options = new HtmlDocumentExporterOptions();
                    options.EmbedImages = true;
                    options.AnchorImagesToPage = true;
                    workbook.ExportToHtml(resultStream, options);
                    resultStream.Seek(0, SeekOrigin.Begin);
                    return resultStream;
                }
            }
        }
    }
    

Create a Dockerfile

Create a Dockerfile within your project folder. This file contains instructions required to build a Docker image and deploy it inside a container. Add the following commands to your Dockerfile:

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build-env
WORKDIR /app

# Copy the .csproj file and restore the project's dependencies
COPY *.csproj ./
# Specify your DevExpress NuGet Feed URL as the package source
RUN dotnet nuget add source https://nuget.devexpress.com/{your-feed-authorization-key}/api
RUN dotnet restore

# Copy project files and build the application
COPY . ./
RUN dotnet publish -c Release -o /app/publish

# Build runtime image
FROM mcr.microsoft.com/dotnet/aspnet:6.0
WORKDIR /app

# Install the latest version of the libgdiplus library to use System.Drawing in the application
RUN apt update
RUN apt install -y libgdiplus libc6 libc6-dev
RUN apt install -y fontconfig libharfbuzz0b libfreetype6

# Optional. Install the ttf-mscorefonts-installer package 
# to use Microsoft TrueType core fonts in the application
RUN echo "deb http://ftp.debian.org/debian/ stretch contrib" >> /etc/apt/sources.list
RUN apt-get update
RUN apt-get install -y ttf-mscorefonts-installer  

COPY --from=build-env /app/publish .
# Define the entry point for the application
ENTRYPOINT ["dotnet", "DocumentConversionWebApi.dll"]

Add a .dockerignore file to your project. Exclude the following folders from the build context to increase build performance:

bin/
obj/

Build and Run the Docker Image

Use the following terminal commands to build and run your Docker image:

docker build -t documentconversionwebapi .
docker run -d -p 8080:80 documentconversionwebapi

Test the Application

This tutorial uses the Thunder Client extension to test the created Web API application.

  1. Install and start Thunder Client in Visual Studio Code. Click New Request to create a new HTTP request to the API endpoint. Select the POST method in the drop-down list and enter the following URL in the input field:

    http://localhost:8080/ConvertFile

    Create a new HTTP POST request

  2. Specify a Request Body for the POST request. Switch to the Body tab and click Form.

    Specify the request body type

  3. Select the Files check box to display the Files section. Enter file as the field name and click Choose File to select a document you need to convert to HTML.

    Upload a file for conversion

  4. Click Send to upload the selected file to the server and convert this document to HTML.

    Send the request

    The result is displayed on the Response tab. Click Preview to see the generated HTML document.

    Response from the server

Troubleshooting

System.Drawing.Common is Supported on Windows Only

With the .NET 6 release, the System.Drawing.Common library is compatible with Windows only. Applications that are built for non-Windows platforms now throw the TypeInitializationException and PlatformNotSupportedException exceptions. Refer to the following breaking change for more information: System.Drawing.Common only supported on Windows.

You can set the System.Drawing.EnableUnixSupport runtime configuration switch to true in the runtimeconfig.json file to enable support for non-Windows operating systems and to avoid runtime exceptions:

{
   "configProperties": {
      "System.Drawing.EnableUnixSupport": true
   }
}

However, this runtime configuration switch will not be supported in .NET 7 and higher, and all apps that use Sytem.Drawing.Common on non-Windows platforms will throw PlatformNotSupportedException. To address this issue, we plan to implement our own cross-platform rendering engine based on the SkiaSharp library. See the following blog post for details: DevExpress Cross-Platform Products – Getting Ready for .NET 7.

See Also