Dockerize an Office File API Application
- 10 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.
Prerequisites
- .NET 8.0 SDK
- Visual Studio Code
- Docker
- Thunder Client (a Rest API Client Extension for Visual Studio Code)
Create an Application
Create a folder for your project (
DocumentConversionWebApiin this example) and open this folder in Visual Studio Code.Click View → Terminal in the main menu to open the integrated terminal.
Use the dotnet new command to create a new Web API application.
dotnet new webapi -o DocumentConversionWebApi cd DocumentConversionWebApiThe image below shows the created project’s 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.
Install the DevExpress.Document.Processor and DevExpress.Drawing.Skia NuGet packages as described in the following help topic: Use NuGet Packages to Install Office File API Components.
Important
These packages are available as part of the DevExpress Office File API Subscription or DevExpress Universal Subscription.
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 { [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:
# Build runtime image
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
# Install the latest version of font libraries
RUN apt update &&\
apt install -y libc6 libicu-dev libfontconfig1
# (Optional step) Install the ttf-mscorefonts-installer package
# to use Microsoft TrueType core fonts in the application
RUN echo "deb http://ftp.debian.org/debian/ bookworm contrib" >> /etc/apt/sources.list
RUN apt-get update
RUN apt-get install -y ttf-mscorefonts-installer
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
# Copy the project file
COPY ./DocumentConversionWebApi.csproj ./
# Restore as distinct layers
RUN dotnet restore
# Publish a release
FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "DocumentConversionWebApi.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=build /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.
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
Specify a Request Body for the POST request. Switch to the Body tab and click Form.

Select the Files check box to display the Files section. Enter
fileas the field name and click Choose File to select a document you wish to convert to HTML.
Click Send to upload the selected file to the server and convert this document to HTML.

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

Run Office File API in Minimal / Chiseled Linux Containers
This section applies to applications deployed in minimal Linux environments such as:
- .NET chiseled images
- Distroless containers
- Images without a package manager
- Environments without
fontconfigor system fonts
Example base images:
mcr.microsoft.com/dotnet/aspnet:10.0-noble-chiseled-composite-extra
mcr.microsoft.com/dotnet/sdk:10.0-noble
Key Differences from Regular Linux Distributions
Minimal/chiseled images:
- Do not include
fontconfig - Do not include
/usr/share/fonts - Do not allow to install native packages with
apt-get - Do not support system font discovery
Due to these limitations, applications must meet the following criteria:
1. Use the Skia Drawing Engine
Set the DrawingEngine property to Skia:
2. Use SkiaSharp Native Assets Without System Dependencies
Install the SkiaSharp.NativeAssets.Linux.NoDependencies NuGet package.
If your dependency graph includes SkiaSharp.NativeAssets.Linux transitively, exclude its runtime assets:
<ItemGroup>
<PackageReference Include="SkiaSharp.NativeAssets.Linux"
Version="3.119.2" ExcludeAssets="runtime"
PrivateAssets="all" />
</ItemGroup>
This configuration removes the libfontconfig.so.1 dependency.
3. Include Fonts in the Application
Minimal and chiseled images cannot discover system fonts. You need to include the required TTF files in the application:
<ItemGroup>
<None Include="*.ttf" CopyToPublishDirectory="Always" />
</ItemGroup>
public static int Main(string[] args) {
string[] fonts = ["Inter.ttf", "SegoeUI.ttf"];
string[] fontFiles = [.. fonts.Select(f => Path.Combine(baseDir, f))];
}
4. Register Fonts Explicitly
Register fonts manually before you load documents:
foreach (var fontPath in fontFiles) {
DXFontRepository.Instance.AddFont(fontPath);
}
// ...
using var richEditDocumentServer = new RichEditDocumentServer();
richEditDocumentServer.LoadDocument(fileName, DocumentFormat.Docx);
Refer to the following help topic for more information: Load and Use Custom Fonts.
Example: Chiseled Container (No System Dependencies)
The following docker file deploys an application to a .NET chiseled image that does not include fontconfig or system fonts:
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src
COPY . .
RUN dotnet publish -c Release -o /app
FROM mcr.microsoft.com/dotnet/aspnet:10.0-noble-chiseled-composite-extra
WORKDIR /app
COPY --from=build /app .
ENTRYPOINT ["dotnet", "YourApp.dll"]
public static int Main(string[] args) {
//1. Use the Skia Drawing Engine
Settings.DrawingEngine = DrawingEngine.Skia;
string fileName = Path.Combine(AppContext.BaseDirectory, "fontTest.docx");
// 3. Include Fonts in the Application
string[] fonts = ["Inter.ttf", "SegoeUI.ttf"];
string[] fontFiles = [.. fonts.Select(f => Path.Combine(baseDir, f))];
// 4. Register Fonts Explicitly
foreach (var fp in fontFiles) {
DXFontRepository.Instance.AddFont(fp);
}
using (var wordProcessor = new RichEditDocumentServer()) {
Document doc = wordProcessor.Document;
doc.AppendText("This document is generated by Word Processing Document API: Inter font\r\n");
CharacterProperties cp =
doc.BeginUpdateCharacters(doc.Paragraphs[0].Range);
cp.FontName = "Inter";
doc.EndUpdateCharacters(cp);
doc.AppendText("This document is generated by Word Processing Document API: NotoSans font");
CharacterProperties cp1 =
doc.BeginUpdateCharacters(doc.Paragraphs[1].Range);
cp1.FontName = "Noto Sans";
doc.EndUpdateCharacters(cp1);
wordProcessor.SaveDocument(fileName, DocumentFormat.Docx);
using var exportedPdf = new MemoryStream();
wordProcessor.ExportToPdf(exportedPdf);
exportedPdf.Position = 0;
using var ouput = Console.OpenStandardOutput();
exportedPdf.CopyTo(ouput);
ouput.Flush();
Log("Done.");
}
}