Licensing
Capabilities, license tiers, and the license service
This page is the runtime reference for how a license shapes Doconut's behavior: what each license state allows, how capabilities are granted, and how to inspect all of it from code. (For loading a license, see Getting Started → License Setup.)
License states and what they do
| State | Opens documents? | Watermark | Capabilities |
|---|---|---|---|
| Full (paid) license (within its subscription/update window) | Yes | None | The ones purchased (Has* flags) |
| Temporary license (Developer/NFR — the evaluation license, before its expiry date) | Yes | None | All — blanket grant (the eval funnel) |
| Expired (a temporary license past its expiry date, or a paid subscription past its renewal date) | Yes | Evaluation watermark | None granted |
| No license file at all | Yes | Evaluation watermark | None granted |
| Found but rejected (invalid signature, tampered, blacklisted, or a build newer than the license's version window) | No — LicenseException on every open | — | — |
Two consequences worth internalizing:
- A missing license is not a temporary license. With no license file, pages render watermarked and no capability (search, annotation, plugins) is active. The full-featured, unwatermarked experience requires an actual Temporary license (get one).
- Only a rejected license blocks opening. Calendar/subscription expiry degrades to watermarked rendering; but deploying a build newer than the license's version window is rejected and fails fast with a
LicenseException, so you catch it at deploy — not by silently shipping watermarked output. That exception (fromOpenDocumentAsync) carries the reason fromLicense.RejectionMessage.
Capabilities
Doconut gates optional functionality by capability. Today those are the opt-in Converter and DICOM plugins plus the built-in Search and Annotation features, each granted by your license. The base viewer is not a capability — it is the prerequisite, surfaced as IsViewerLicensed:
bool viewerLicensed = lic.IsViewerLicensed; // non-TRIAL license present AND covering this build's versionThe single gate the whole pipeline uses is IsCapabilityGranted:
bool searchGranted = lic.IsCapabilityGranted(LicenseCapability.Search);Its logic, verbatim from the implementation: an active (non-expired) Temporary license grants every capability — including capabilities that don't have a dedicated purchase flag yet; a real purchased license grants exactly its Has* flags and is default-deny for anything unmapped. (A legacy TRIAL-type file is not an entitlement — it is treated as unlicensed: watermarked, nothing granted.)
Temporary licenses
Normal Search and Annotation use their existing capabilities directly.
Temporary (Developer/NFR) licenses are marked by an ExpiryNote tag and carry a hard expiry date:
| Member | Meaning |
|---|---|
IsTemporary | An ExpiryNote tag is present (detection is by tag presence — never match the note's text, it's dynamic) |
ExpiryNote | Informational text embedded in the license |
LicenseExpiry | The hard expiry date (DateTime?) |
Expiry semantics differ by tier: a temporary license expires on its LicenseExpiry date only (its subscription window is ignored; a temporary license missing the date is treated as expired, fail-safe). Every other license expires on its subscription/update-window date.
IDoconutLicenseService reference
Inject IDoconutLicenseService (namespace Doconut.Core.Interfaces; registered as a singleton — the license is parsed once at startup):
| Member | Meaning |
|---|---|
License | Full DoconutLicenseInfo snapshot (below) |
IsTrial | A legacy TRIAL-type file (treated as unlicensed — not an entitlement) |
IsTemporary / ExpiryNote / LicenseExpiry | Temporary-license markers |
IsExpired | Expired per the tier rules above |
IsVersionValid | This build falls within the license's support window |
IsViewerLicensed | Non-TRIAL file found and version covered — base prerequisite |
IsCapabilityGranted(cap) | The single capability gate |
HasSearch HasAnnotation HasConverter HasDicom | Released per-capability purchase flags — use IsCapabilityGranted for the temporary-aware answer |
IsValidForDomain(host) | Host coverage; V4 licenses use the wildcard *.* |
LicenseRejectionReason | Non-empty ⇒ opening is blocked with this message |
DoconutLicenseInfo exposes the display-friendly snapshot for admin panels: Owner, Email, LicenseType, Domain, IsLicenseFileFound, IsVersionValid, IsTrial, IsExpired, the Has* flags, the temporary-license fields, and RejectionMessage.
// Feature-flag your UI from the same source of truth the SDK uses
app.MapGet("/api/features", (IDoconutLicenseService lic) => Results.Ok(new
{
viewer = lic.IsViewerLicensed || lic.IsTemporary,
search = lic.IsCapabilityGranted(LicenseCapability.Search),
annotation = lic.IsCapabilityGranted(LicenseCapability.Annotation),
conversion = lic.HasConverter,
dicom = lic.HasDicom,
}));Health check
AddDoconut() registers a "doconut" health check that reports license/expiry state through the standard ASP.NET Core mechanism:
app.MapHealthChecks("/health");Wire it into your monitoring and an expiring subscription becomes an alert instead of a support ticket.
Version upgrades
A license covers a version window. Updating the NuGet package to a build newer than that window makes the license invalid for this build: IsVersionValid turns false and opening is blocked with a LicenseException (the reason is in License.RejectionMessage) — deliberately fail-fast, so a stale or unlicensed build is caught at deploy rather than silently watermarking production output. Renew the subscription, replace the .lic, and restart the application so AddDoconut() loads the new license.
이 페이지가 도움이 되었나요?