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
- Performance benchmarks
- Package on NuGet