Plugin System

Extend the viewer with plugins

Doconut's core stays lean; optional functionality ships as plugins — separate NuGet packages that contribute viewers or services and are switched on by your license. This page explains the registration model, how license gating behaves at runtime, and how to plug in your own viewer.

Registering a plugin

Each plugin package exposes one plugin class. You register it once, at startup:

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

AddPlugin<TPlugin>() instantiates the plugin and invokes its Register callback against the plugin registry held on DoconutOptions. Everything a plugin contributes is tagged with the plugin's required capability. AddDoconut() validates registered plugins immediately: a missing license, legacy TRIAL file, or paid license without the capability fails startup with InvalidOperationException. A Temporary/Demo registration is retained across expiry, but its runtime capabilities are revoked after the expiry date.

The contract

A plugin implements a deliberately small interface:

text
public interface IDoconutPlugin
{
    string Name { get; }                          // e.g. "Doconut DICOM Viewer"
    LicenseCapability RequiredCapability { get; } // the license gate
    void Register(IDoconutPluginBuilder builder); // contribute viewers/services
}

Inside Register, the builder accepts two kinds of contributions:

  • builder.RegisterViewer(".dcm", () => new DicomViewer()) — a viewer for a file extension,
  • builder.RegisterService<TContract>(() => …) — a typed service other parts of the pipeline can look up.

Capabilities and gating

Capabilities are the license units. Converter and Dicom ship as opt-in plugins; Search and Annotation are built-in features gated the same way. The base viewer is not a capability — it is the prerequisite, exposed as IsViewerLicensed on the license service.

Startup validation normally prevents an unlicensed plugin from entering the request pipeline. The viewer factory also applies two defensive runtime rules, which matter if entitlement changes after startup:

  • Plugin overrides a built-in viewer (a plugin claims an extension the built-in registry also handles): with the capability licensed, the plugin viewer wins; without it, Doconut silently falls back to the built-in viewer. Users still see their document — they just don't get the plugin feature.
  • Plugin-only format (e.g. .dcm — DICOM has no built-in viewer): without the capability the open call fails hard:
text
LicenseException: This document type requires the 'Dicom' plugin license.

An active Temporary license grants every capability (with clean, unwatermarked base viewing). This is a classic source of go-live surprises: registering the same plugins with a purchased license that omits one of their capabilities makes AddDoconut() fail during startup. Compare IsCapabilityGranted(...) against your plan before deploying. The flip side: with no license at all, nothing is granted — a missing license is not a Temporary license.

The same gating shows up client-side: Viewer.ReferenceScripts() and ReferenceCss() emit the script/style bundles for the license-gated features (search, annotation, …) only when the license enables them, so the widget's UI stays consistent with what the server will actually do.

Feature and plugin map

The product UI uses “plugin” as a broad feature label, but server registration differs:

FeatureHow it is enabledCapabilityContributes
AnnotationBuilt into the viewer; include annotation resourcesAnnotationBrowser authoring, session persistence, and burned-in exports
SearchBuilt into searchable format viewers; include search resources and enable extraction where requiredSearchNative text index, highlights, and result navigation
ConverterInstall Doconut.NET6.Converter and register ConverterPluginConverterC# conversion service and optional web widget
DICOMInstall Doconut.NET6.Dicom and register DicomPluginDicomMedical-image viewing for .dcm and .ima

Annotation and normal Search do not use AddPlugin<TPlugin>(); their bundles are emitted only when the license grants the corresponding capability. Converter and DICOM are the released opt-in IDoconutPlugin implementations for this documentation set.

The approved .NET 6 artifacts contain Doconut.NET6.Converter and Doconut.NET6.Dicom at the same version as the core package.

Released plugin packages

PluginPackageCapabilityContributes
ConverterDoconut.NET6.ConverterConverterDocument conversion capability
DICOMDoconut.NET6.DicomDicomMedical-image viewing (.dcm — plugin-only format)

Each has a dedicated page under Plugins with its configuration and usage.

Custom viewers — your own format handler

You can plug a viewer into the pipeline without writing a plugin package, straight from Program.cs:

text
builder.Services.AddDoconut(options =>
{
    options.RegisterViewer(
        ".myext",
        () => new MyCustomViewer(),               // implements IFormatViewer
        () => new ImageConfig { ImageResolution = 150 }); // optional default config
});

Custom viewers take precedence over everything — built-ins and plugins alike — and are not license-gated (they are your code). The factory falls back to an ImageConfig when you don't supply a default config.

Takeaways

  • Plugins are registered explicitly and their LicenseCapability is validated during AddDoconut() — missing or insufficient non-temporary entitlement fails fast.
  • Override-style plugins degrade gracefully; plugin-only formats fail with a LicenseException.
  • An active Temporary license unlocks everything; production unlocks what you bought. Verify with IDoconutLicenseService before shipping.

Was this page helpful?