Skip to content

C# / .NET Office Library — Quick Start

OfficeOxide is the .NET binding for the Rust office_oxide library. It gives .NET applications fast, allocation-conscious parsing, conversion, and editing of DOCX / XLSX / PPTX / DOC / XLS / PPT — with AOT-compatible LibraryImport P/Invoke under the hood.

Install

dotnet add package OfficeOxide --version 0.1.0

Requires .NET 8 or .NET 10. The NuGet package ships prebuilt native libraries for win-x64, linux-x64, linux-arm64, osx-x64, osx-arm64 under runtimes/<rid>/native/. dotnet publish places the right one next to your binary automatically.

Read a document

using OfficeOxide;

using var doc = Document.Open("report.docx");
Console.WriteLine(doc.PlainText());

Core API

Document is the read-only handle; dispose it (preferably with using) to free native memory.

using OfficeOxide;

using var doc = Document.Open("file.xlsx");

Console.WriteLine(doc.Format);        // "xlsx"
Console.WriteLine(doc.PlainText());
Console.WriteLine(doc.ToMarkdown());
Console.WriteLine(doc.ToHtml());
Console.WriteLine(doc.ToIrJson());

doc.SaveAs("file.docx");              // target inferred from extension

Async wrapper for blocking IO:

using var doc = await Document.OpenAsync("huge.pptx", ct);

Open from bytes (no temp file needed):

byte[] data = File.ReadAllBytes("report.docx");
using var doc = Document.FromBytes(data, "docx");

format must be "docx", "xlsx", "pptx", "doc", "xls", or "ppt".

Static helpers for one-shot calls:

string text = OfficeOxide.ExtractText("file.docx");
string md   = OfficeOxide.ToMarkdown("file.pptx");
string html = OfficeOxide.ToHtml("file.xlsx");

string? fmt = Document.DetectFormat("mystery.bin"); // null if unsupported
Console.WriteLine(Document.Version);                // "0.1.0"

Editing

Editing preserves every unmodified OPC part (images, charts, relationships) on save. DOCX, XLSX, and PPTX only.

using OfficeOxide;

using var ed = EditableDocument.Open("template.docx");
long n = ed.ReplaceText("{{name}}", "Alice");
Console.WriteLine($"{n} replacements");
ed.Save("out.docx");

ReplaceText returns the replacement count (0 on XLSX — use SetCell instead).

Replace text in DOCX / PPTX

using var ed = EditableDocument.Open("slides.pptx");
ed.ReplaceText("Q3", "Q4");
ed.ReplaceText("2024", "2025");

byte[] bytes = ed.SaveToBytes();
File.WriteAllBytes("slides_q4.pptx", bytes);

Set XLSX cells (four overloads)

using var wb = EditableDocument.Open("budget.xlsx");

wb.SetCell(0u, "A1", "Total");        // string overload
wb.SetCell(0u, "B1", 42.5);           // double overload
wb.SetCell(0u, "C1", true);           // bool overload
wb.SetCellEmpty(0u, "D1");            // clear a cell

wb.Save("budget.xlsx");

sheetIndex is zero-based; cellRef is standard spreadsheet notation.

Format-agnostic IR

ToIrJson() returns a JSON string matching the Rust DocumentIR shape:

using System.Text.Json;

using var doc = Document.Open("report.docx");
string json = doc.ToIrJson();

using var ir = JsonDocument.Parse(json);
foreach (var section in ir.RootElement.GetProperty("sections").EnumerateArray())
{
    if (section.TryGetProperty("title", out var t) && t.ValueKind != JsonValueKind.Null)
        Console.WriteLine(t.GetString());
}

Bytes-based pipelines

using var http = new HttpClient();
byte[] data = await http.GetByteArrayAsync("https://example.com/file.docx");
using var doc = Document.FromBytes(data, "docx");
Console.WriteLine(doc.ToMarkdown());

Legacy formats

using var legacy = Document.Open("old.xls");
legacy.SaveAs("modern.xlsx");

AOT / trimming

The project sets IsAotCompatible=true and IsTrimmable=true. All P/Invoke uses LibraryImport source generators, so dotnet publish -c Release -p:PublishAot=true yields a single self-contained executable.

Errors

Failures throw OfficeOxideException carrying a typed Code and Operation:

try
{
    using var doc = Document.Open("missing.docx");
}
catch (OfficeOxideException ex)
{
    Console.WriteLine($"code={ex.Code} op={ex.Operation}");
}

Calling methods on a disposed handle throws ObjectDisposedException.

Code Name Meaning
0 Ok success
1 InvalidArg null / empty / wrong format string
2 Io filesystem error
3 Parse malformed document
4 Extraction parsed but rendering failed
5 Internal bug — please file an issue
6 Unsupported extension / feature not supported

Troubleshooting

Symptom Fix
DllNotFoundException: office_oxide Native library wasn’t copied next to your binary. Run dotnet publish rather than raw dotnet build.
BadImageFormatException on Windows CPU architecture mismatch — deploy the matching win-x64 or win-arm64 build.
OfficeOxideException with code Unsupported on .doc Ensure the extension is lowercase or pass the format explicitly via FromBytes.
Trimmed output missing symbols Add OfficeOxide to <TrimmerRootAssembly>.
macOS “developer cannot be verified” Run xattr -d com.apple.quarantine /path/to/liboffice_oxide.dylib or sign the bundle.

See also