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, what happens at startup when a license does not cover a plugin, and how to plug in your own viewer.

Registering a plugin

Each plugin package exposes one plugin class. Register it once, in Application_Start:

csharp
Doconut.DoconutHost.Initialize(options =>
{
    options.AddPlugin<Doconut.Plugins.Converter.ConverterPlugin>();
    options.AddPlugin<Doconut.Plugins.Dicom.DicomPlugin>();
});
// A registered plugin whose license is missing throws here, in Application_Start, and the
// site then answers every request with an empty 500. The reason is in the Windows event log.

AddPlugin<TPlugin>() creates the plugin and lets it register its contributions with DoconutOptions. Everything a plugin contributes is tagged with the plugin's required capability, and DoconutHost.Initialize checks every registered plugin against the license before the site serves its first request.

A missing plugin license stops the site

When no active license grants a registered plugin's capability — no license at all, a legacy TRIAL file, or a paid license without that capability — DoconutHost.Initialize throws InvalidOperationException from Application_Start:

text
The Converter plugin is registered via AddPlugin but no active license grants Converter.
Remove the AddPlugin<...>() call or install a license (or trial/demo) that includes Converter.

In System.Web, an exception in Application_Start does not produce an error page. Every request answers an empty 500, the IIS log shows nothing useful, and the message appears only in the Windows event log (Application log, source ASP.NET). When a site stops responding right after an AddPlugin line was added, check the license files in wwwroot first — see License Setup.

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 contribution:

  • 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 keeps an unlicensed plugin out of the request pipeline. The viewer factory also applies two defensive rules, which matter if entitlements change while the site runs:

  • A plugin that overrides a built-in viewer (it claims an extension a built-in viewer also handles): with the capability licensed, the plugin's viewer wins; without it, Doconut falls back to the built-in viewer. Users still see their document; they just don't get the plugin's behavior.
  • A plugin-only format (.dcm and .ima — DICOM has no built-in viewer): without the capability, opening fails:
text
LicenseException: This document type requires the 'Dicom' plugin license.

An active Temporary license grants every capability. That is a classic go-live surprise: the same AddPlugin lines that ran during evaluation stop the site when the purchased license omits one of those capabilities. Compare IsCapabilityGranted(...) with what you bought before deploying. With no license at all, nothing is granted — a missing license is not a Temporary license.

The same gating reaches the browser: Viewer.ReferenceScripts() and ReferenceCss() emit the files for license-gated features (Search, Annotation) only when the license grants them, so the page never offers a feature the server will refuse.

Feature and plugin map

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

Annotation and Search do not use AddPlugin<TPlugin>(). Converter and DICOM each have a page under Plugins with their configuration and usage. On this package, DICOM renders pages, frames, and animations, but does not read technical metadata — see DICOM Plugin.

Custom viewers — your own format handler

You can plug a viewer into the pipeline without writing a plugin package, directly in Application_Start:

text
Doconut.DoconutHost.Initialize(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. When you supply no default config, the factory uses an ImageConfig.

Takeaways

  • Plugins are registered explicitly in DoconutHost.Initialize, and their capabilities are validated there; a missing entitlement stops the site with an empty 500 whose reason is in the Windows event log.
  • Override-style plugins degrade gracefully; plugin-only formats fail with a LicenseException.
  • An active Temporary license unlocks everything; production unlocks what you bought. Check with IDoconutLicenseService before shipping.

Esta página foi útil?