Migrate from the classic .NET 6 integration

Move an existing Doconut.NET6 application to the current DI and async API

Doconut has two distinct .NET 6 integrations. They can use the same Doconut.NET6 package name, so identify the generation from the APIs in the application before changing packages, startup, licenses, or browser resources.

Which .NET 6 integration are you using?

If the project contains…Generation
app.MapWhen(... "DocImage.axd" ...)Legacy / classic
new Viewer(_cache, _accessor, ...)Legacy / classic
Viewer.DoconutLicense(...) or Viewer.SetLicensePlugin(...)Legacy / classic
Manually copied docViewer.js, documentLinks.js, or docViewer.UI.jsLegacy / classic
builder.Services.AddDoconut(...)Current integration
app.UseDoconutResources() plus app.UseDoconut()Current integration
Viewer supplied by dependency injectionCurrent integration
await viewer.OpenDocumentAsync(...)Current integration

If both columns appear in the same application, treat the migration as incomplete. Do not send one document token through resources or middleware from the other generation.

Why the NuGet package name may not tell you

Both generations have shipped under the Doconut.NET6 package ID. A package reference, lock file, or cached .nupkg therefore does not identify the hosting API by itself. Record the exact package version and inspect Program.cs, viewer construction, document opening, and browser scripts together.

The current release audited for this guide is Doconut.NET6 26.7.0. Its optional public packages are Doconut.NET6.Converter and Doconut.NET6.Dicom, pinned to the same release version as the core package.

Before you migrate

  1. Create a branch and a deployable backup of the existing application.
  2. Record the exact core and plugin package versions.
  3. Inventory every DocImage.axd mapping, new Viewer(...) call, license-loading call, copied Doconut script, custom toolbar action, and document-open endpoint.
  4. Preserve the current .lic files and deployment secrets outside source control.
  5. Capture a representative set of PDF, Office, image, CAD, email, DICOM, searchable, password-protected, and annotated documents.
  6. Record the existing session timeout, security behavior, fonts, and platform settings.

Migrate one environment before changing production. The current integration changes service lifetime, request routing, session ownership, and client resource delivery.

Package and license compatibility

Replace or update the core package deliberately; do not rely on the identical package ID to select the new API. The default command installs the latest stable release:

bash
dotnet add package Doconut.NET6

For a reproducible migration to the release audited by this guide, pass the version as a separate option:

bash
dotnet add package Doconut.NET6 --version 26.7.0

Keep every Doconut plugin at the same version as the core package. The current integration loads licenses once during AddDoconut(), using this precedence:

text
LicenseStream > LicenseContent > LicensePath > automatic discovery

Automatic discovery looks for Doconut.lic, then Doconut.Viewer.lic and companion Doconut.Viewer.<Capability>.lic files. A classic call to Viewer.DoconutLicense(...) or Viewer.SetLicensePlugin(...) is not a current startup mechanism. Move the license to DoconutOptions, keep companion files together when using automatic discovery, restart after changing a license, and verify capabilities through IDoconutLicenseService.

Do not assume that the presence of an old plugin license proves entitlement for a current plugin build. Test Viewer, Search, Annotation, Converter, and DICOM separately with the approved release artifacts.

Startup and dependency injection

Classic applications construct Viewer with ASP.NET cache and request-accessor dependencies:

csharp
// Classic integration — contrast only; do not compile this against the current SDK.
var viewer = new Viewer(_cache, _accessor, licenseFilePath);

The current integration registers Doconut once and receives Viewer from dependency injection:

csharp
builder.Services.AddDoconut(options =>
{
    options.LicensePath = "Doconut.lic";
    options.UnsafeMode = false;
});
builder.Services.AddSession();

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

Viewer is a transient service. The document session manager and its cache own the longer-lived document state, not the particular injected Viewer instance.

Middleware and resource routing

Remove the classic MapWhen branch that detects DocImage.axd:

csharp
// Classic integration — remove during the cutover.
app.MapWhen(
    context => context.Request.Path.ToString().EndsWith("DocImage.axd"),
    branch => branch.UseDoconut(new DoconutOptions()));

In the current pipeline:

  1. call UseSession() before Doconut while session security is enabled;
  2. call UseDoconutResources() before UseDoconut();
  3. keep ResourcesPath, the generated resource URLs, and client ResPath aligned;
  4. when mapping UseDoconut() to a branch, keep that branch and client BasePath aligned.

MiddlewarePath is validated configuration; it does not create an ASP.NET Core branch by itself. Use either the simple pipeline in the compiling sample above or an explicit app.Map("/doconut", branch => branch.UseDoconut()) arrangement used consistently by the client.

Viewer construction and lifetime

Remove application-owned caches of Viewer objects. Inject Viewer into an endpoint, Razor page, controller, or scoped application service:

csharp
app.MapPost("/api/open", async (Viewer viewer) =>
{
    var token = await viewer.OpenDocumentAsync("wwwroot/files/Sample.pdf");
    return Results.Ok(new { token });
});

The returned token identifies a server-side document session. Treat it as a bearer credential: do not log it, persist it, or place it in analytics.

Opening and closing documents

Replace synchronous OpenDocument(...) with OpenDocumentAsync(...):

csharp
// Current .NET 6 integration: Viewer comes from DI and document opening is asynchronous.
var token = await viewer.OpenDocumentAsync(path, new PdfConfig { AllowSearch = true });

Current overloads accept a file path or stream, an optional format config, optional DocOptions, and a cancellation token. Close the server session explicitly when the browser no longer needs it:

csharp
viewer.CloseDocument(token);

Do not reuse a classic token after the cutover. Open each document again through the current API.

Configuration classes

The current API separates concerns:

ConcernCurrent type
Middleware paths, licensing, plugin registrationDoconutOptions
Password, timeout, security, watermarkDocOptions
Format rendering and DPIPdfConfig, WordConfig, ExcelConfig, and other BaseConfig types
Browser widget defaultsViewerConfig or the equivalent JavaScript options
Generated CSS and scriptsCssConfig and ScriptConfig

Do not carry DocOptions.ImageResolution forward as the rendering control. It is obsolete; set BaseConfig.ImageResolution on the format-specific config. Review all defaults instead of assuming a classic config has the same behavior.

Viewer toolbar, Search, and Annotation

Do not migrate the old scripts one by one. The current reference applications compose one complete page package:

  1. emit Viewer CSS and licensed Search/Annotation CSS with ReferenceCss;
  2. render the application-owned Viewer toolbar;
  3. render searchBarMount, annBarMount, and the required Viewer mount;
  4. emit Viewer and licensed module scripts with ReferenceScripts;
  5. load the application's own viewerToolbar.js;
  6. initialize one objViewer;
  7. initialize the licensed Search and Annotation Ribbons;
  8. call attach(objViewer) on each Ribbon;
  9. open the document and call objViewer.View(token).

Search and Annotation are modules attached to the same Viewer, not independent toolbars. The main toolbar belongs to the host application; the Search and Annotation Ribbons are embedded, capability-gated resources.

Remove manually copied classic files such as documentLinks.js and docViewer.UI.js only after the current page works with resources emitted by ReferenceCss and ReferenceScripts.

Plugin registration

Classic static plugin-license methods do not register current plugins. Install and register each released package explicitly:

csharp
builder.Services.AddDoconut(options =>
{
    options.AddPlugin<Doconut.Plugins.Converter.ConverterPlugin>();
    options.AddPlugin<Doconut.Plugins.Dicom.DicomPlugin>();
});

AddDoconut() validates registered plugin capabilities at startup. Converter and DICOM are released .NET 6 plugins. Normal Search and Annotation are built-in licensed features, not AddPlugin<TPlugin>() packages.

Session and document security

The current integration binds documents to opaque tokens and cached sessions. With the default UnsafeMode = false, UseDoconut() adds document-access security and the host must configure ASP.NET session:

csharp
builder.Services.AddSession();
app.UseSession();

Keep DocOptions.IsSecured = true unless a reviewed design requires otherwise. Never use UnsafeMode = true as a migration shortcut. Test requests with no token, a malformed token, an expired token, and a token from a different browser session.

The Distributed reference application adds access tickets and transport details. Those APIs are not required for a normal single-node migration.

Testing the migration

At minimum, verify:

  • application startup with the production license and every registered plugin;
  • Viewer CSS/scripts and all page-image requests under the chosen paths;
  • document open, navigation, zoom, thumbnails, print, and explicit close;
  • Search on a text-bearing document and the non-searchable state of an image-only file;
  • Annotation load, save, export, and capability gating;
  • Converter target discovery, output, download, and watermark state;
  • DICOM pages, frames, and animation; .NET 6 technical metadata is unavailable;
  • password-protected documents, custom fonts, non-Latin text, and configured timeouts;
  • cross-session token rejection and expired-session behavior;
  • mobile, dark mode, and the production reverse-proxy path.

Rollback plan

Keep the classic deployment artifact, matching packages, license files, and copied browser resources together. A safe rollback switches the entire application generation; it does not mix a classic server with current scripts or a current server with classic DocImage.axd calls.

Before cutover, document:

  • the deployment slot or artifact used for rollback;
  • the database/cache impact, if any;
  • how active document sessions will be invalidated;
  • the health check and smoke document used to decide rollback;
  • who can restore the previous package set and configuration.

Legacy documentation

The translated classic manual remains available at Legacy .NET 6 setup. The new Classic integration gateway explains the same identification signals and links back to this migration guide.

Keep the historic URL in bookmarks and support tickets while classic installations still exist. It documents a different generation and is not redirected to the current API.

Was this page helpful?