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.
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
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:
| Service | Lifetime | Role |
|---|---|---|
DoconutOptions | Singleton | The configuration object |
| Session cache service | Singleton | Token → session cache (IMemoryCache is registered too) |
IDoconutLicenseService | Singleton | License loaded once at startup (precedence: LicenseStream → LicenseContent → LicensePath → auto-search) |
| Page-image pipeline | Singleton | Performs image processing for pages (watermark, rotate, scale, annotations) |
| Document security (access store) | Singleton | Grants for token-to-session binding |
Viewer | Transient | The public open/close facade |
DocumentConverter | Transient | Conversion facade — requires the Converter plugin |
DocumentSigner | Transient | Signing facade — requires the Signer plugin (see Signer Plugin) |
DistributedDocumentPublisher | Transient | Publishes 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
DocumentConverterwithoutoptions.AddPlugin<ConverterPlugin>()throws:
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
TRIALfile, or paid license without a registered plugin's capability fails atAddDoconut()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:
app.MapHealthChecks("/health");UseDoconut
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: '/'):
app.MapWhen(
ctx => ctx.Request.Path.Value?.EndsWith("DocImage.axd", StringComparison.OrdinalIgnoreCase) == true,
branch => branch.UseDoconut());UseDoconutResources
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:
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 uploadsThe read side is a separate middleware from the Doconut.Clouds assembly, which ships in the same package:
IApplicationBuilder UseDoconutCloud<THandler>(
this IApplicationBuilder app,
Action<CloudOptions>? configure = null,
string pathPrefix = "/doconut-cloud")
where THandler : BaseCloudHandlerUseDoconutWebFarm(...) and WebFarmOptions do not exist in this release. See the
migration guide for the setting-by-setting mapping.
Ordering recap
app.UseRouting();
app.UseSession(); // call UseSession() before UseDoconut()
app.UseDoconutResources(); // must be registered before UseDoconut()
app.Map("/doconut", branch => branch.UseDoconut()); // or a MapWhen branchWas this page helpful?