DoconutExtensions

Service and middleware registration

DoconutExtensions (namespace Doconut.Middleware) is the static class with the three calls every Doconut host makes: one service registration and two middleware registrations.

csharp
builder.Services.AddDoconut(options => { /* … */ });
// …
app.UseSession();          // call UseSession() before UseDoconut()
app.UseDoconutResources(); // must be registered before UseDoconut()
app.Map("/doconut", branch => branch.UseDoconut());

UseDoconut() answers every request that reaches it, so mount it on its own branch with app.Map.

AddDoconut

text
IServiceCollection AddDoconut(this IServiceCollection services, Action<DoconutOptions>? configure = null)

Builds the DoconutOptions, validates them fail-fast (see DoconutOptions → Startup validation), and registers the full service graph:

ServiceLifetimeRole
DoconutOptionsSingletonThe configuration object
Session cache serviceSingletonToken → session cache (IMemoryCache is registered too)
IDoconutLicenseServiceSingletonLicense loaded once at startup (precedence: LicenseStream → LicenseContent → LicensePath → auto-search)
Page-image pipelineSingletonPerforms image processing for pages (watermark, rotate, scale, annotations)
Document security (access store)SingletonGrants for token-to-session binding
ViewerTransientThe public open/close facade
DocumentConverterTransientConversion facade — requires the Converter plugin
DocumentSignerTransientSigning facade — requires the Signer plugin (see Signer Plugin)
DistributedDocumentPublisherTransientPublishes a document's artifacts to shared storage
Health check "doconut"—Reports license/expiry state through ASP.NET health checks

There is no equivalent call in the previous .NET Standard library. It constructed new Viewer(cache, accessor) per request and passed options to the middleware; both are replaced by this single registration.

Two behaviors worth knowing:

  • Converter requires its plugin. Resolving DocumentConverter without options.AddPlugin<ConverterPlugin>() throws:
text
InvalidOperationException: No IDocumentConverter is registered. Add the converter plugin: options.AddPlugin<Doconut.Plugins.Converter.ConverterPlugin>().

DocumentSigner follows the same rule: without options.AddPlugin<SignerPlugin>() it throws No IDocumentSigner is registered. Add the signing plugin: options.AddPlugin<Doconut.Plugins.Signer.SignerPlugin>().

  • Plugin entitlement is validated at startup. A missing license, legacy TRIAL file, or paid license without a registered plugin's capability fails at AddDoconut() time. Temporary/Demo registrations survive their expiry date, while runtime gates revoke the expired capabilities.

The health check integrates with the standard ASP.NET Core mechanism — map it if you want license state on your health endpoint:

csharp
app.MapHealthChecks("/health");

UseDoconut

text
IApplicationBuilder UseDoconut(this IApplicationBuilder app)

Adds the Doconut page-image middleware. It serves every request carrying a ?token= query parameter — pages, thumbnails, search, annotations, page actions (the full request table is in Core Concepts → How the Viewer Works) — and answers any other request itself with 404 (or the ShowDoconutInfo banner): it never passes a request on to the rest of the pipeline. Mount it on its own branch, as in the samples on this page. When UnsafeMode is false, the document-security layer is wired in automatically before it.

It takes no arguments. Passing a DoconutOptions instance here was the previous library's shape and no longer compiles.

A common setup keeps the historic DocImage.axd request shape with a MapWhen branch (the client then uses BasePath: '/'):

csharp
app.MapWhen(
    ctx => ctx.Request.Path.Value?.EndsWith("DocImage.axd", StringComparison.OrdinalIgnoreCase) == true,
    branch => branch.UseDoconut());

UseDoconutResources

text
IApplicationBuilder UseDoconutResources(this IApplicationBuilder app)

Serves the embedded JS, CSS, images, and fonts at DoconutOptions.ResourcesPath (default /doconut-res). These are the files that Viewer.ReferenceCss() / ReferenceScripts() emit tags for.

Always call it before UseDoconut(). If the viewer area stays empty and the browser console shows 404s for /doconut-res/..., this call is missing or misplaced.

This is the supported replacement for wiring the embedded-resource handling middleware manually.

Serving from shared storage

Two further registrations exist for deployments where the node that renders a document is not necessarily the node that serves its pages. Both are covered end to end in Distributed Deployments; the signatures are:

text
IServiceCollection AddDoconutDistributedAsyncPublish(this IServiceCollection services, Action<DistributedAsyncPublishOptions>? configure = null)   // opt-in background publish queue
IServiceCollection AddDoconutDistributedWidgets(this IServiceCollection services, Action<DistributedWidgetsOptions> configure)                     // shared backing store for widget uploads

The read side is a separate middleware from the Doconut.Clouds assembly, which ships in the same package:

text
IApplicationBuilder UseDoconutCloud<THandler>(
    this IApplicationBuilder app,
    Action<CloudOptions>? configure = null,
    string pathPrefix = "/doconut-cloud")
    where THandler : BaseCloudHandler

UseDoconutWebFarm(...) and WebFarmOptions do not exist in this release. See the migration guide for the setting-by-setting mapping.

Ordering recap

csharp
app.UseRouting();
app.UseSession();          // call UseSession() before UseDoconut()
app.UseDoconutResources(); // must be registered before UseDoconut()
app.Map("/doconut", branch => branch.UseDoconut()); // or a MapWhen branch

Was this page helpful?