Blazor

A document viewer that behaves inside Blazor

Blazor gives you a component model and a render loop that does not much care for third-party JavaScript. Doconut works with that rather than against it: rendering happens server-side in your own process, and the widget mounts into a plain element you control through the normal interop lifecycle.

75
file extensions, no client parsing
2
hosting models supported
0
WASM payload for rendering

The problem

Why the usual approaches hurt in Blazor

The client-side route means shipping a rendering engine into the browser. In Blazor WebAssembly that lands directly on your download size, and it only ever covers PDF — the moment someone uploads a DOCX or an XLSX you are back to square one.

The iframe-to-Office route means your documents take a trip through somebody else's infrastructure, which is a conversation with your security team you probably do not want to have twice.

Doconut takes the third route. The file is rasterized to page images by your own server, and Blazor only has to host a div. Your component tree never re-renders a viewer it does not own, and the diff engine has nothing to fight with.

Capabilities

What you get in a Blazor app

Blazor Server and WebAssembly

Rendering is server-side either way. In Server the call is direct; in WebAssembly you expose the open call as a minimal API endpoint and hand the returned token to the widget. Both are a handful of lines.

Mounts through OnAfterRenderAsync

Initialise the widget once, after the first render, through the standard JS interop hook. Because Blazor never owns the viewer's internal DOM, subsequent re-renders leave it untouched.

Works with the render-mode you chose

Interactive Server, Interactive WebAssembly, or Auto. The viewer is driven by an opaque token rather than component state, so switching render mode does not change the integration.

No format gaps

The same component opens PDF, DOCX, XLSX, PPTX, DWG, MSG and the rest of the catalogue. You write one viewer page, not one per file family.

Thumbnails, search and print

Navigation UI comes with the widget. You are wiring up a viewer, not building one out of a canvas and a page-number input.

Documents stay on your server

Nothing is streamed to the browser except rendered page images, which matters more in WebAssembly than people expect — the client is, after all, fully inspectable.

Integration

Program.cs and a Blazor page

doconutHost.mount is a few lines of your own JavaScript that calls $('#div_ctlDoc').docViewer({ ... }) and then .View(token). Keeping it outside Blazor is deliberate — the widget's DOM should not be something the renderer tries to reconcile.

Supported platforms

Blazor ServerBlazor WebAssembly.NET 8.NET 6WindowsDocker
csharp
// Program.cs — order matters
builder.Services.AddDoconut(options =>
{
    options.LicensePath = "Doconut.Viewer.lic";
});
builder.Services.AddSession();

app.UseSession();          // before UseDoconut()
app.UseDoconutResources(); // before UseDoconut()
app.UseDoconut();

// Viewer.razor — open server-side, hand the token to the widget
@inject Doconut.Viewer Viewer
@inject IJSRuntime JS

<div id="divDocViewer"><div id="div_ctlDoc"></div></div>

@code {
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (!firstRender) return;

        // Authorize first — the viewer renders whatever you hand it.
        string token = await Viewer.OpenDocumentAsync("wwwroot/files/Sample.pdf");
        await JS.InvokeVoidAsync("doconutHost.mount", token);
    }
}

Details

Worth knowing before you start

  • The widget is a jQuery plugin, so jQuery has to load before the viewer scripts.
  • UseSession() and UseDoconutResources() must both be registered before UseDoconut().
  • In WebAssembly the open call belongs on the server — expose it as a minimal API endpoint and return only the token.
  • The token is opaque. Do not put it in a query string you log, and do not cache it in component state longer than the page lives.

Frequently asked questions

Does this work in Blazor WebAssembly, or only Server?

Both. Rendering always happens server-side, so in WebAssembly you add one endpoint that calls OpenDocumentAsync and returns the token. The client never parses a document, which is exactly why the WASM payload stays unaffected.

Will Blazor's renderer fight with the viewer's DOM?

No, provided you mount into an element Blazor treats as a leaf. Render an empty div and let the widget populate it through interop — the diff engine has no children to reconcile.

Do I need a separate viewer page per file type?

No. One page handles the whole catalogue. The format is detected from the document you open, not selected by you in advance.

Try it against your own documents

A temporary licence takes a few minutes to request and runs entirely on your own machine. The files that matter are the ones already breaking your current viewer.