Viewer

The main document viewer class

Viewer (namespace Doconut) is the public entry point for opening documents from Razor pages, MVC controllers, Blazor components, or minimal APIs. It is sealed, registered as a transient service by AddDoconut(), and resolved via constructor injection — never construct it directly.

Viewer holds no per-request state and intentionally does not implement IDisposable: document sessions live independently in the session cache, so disposing the service could never tear down an open document (see Core Concepts → How the Viewer Works).

OpenDocumentAsync

Opens a document and returns the session token the client widget uses for all subsequent requests.

OverloadUse when
Task<string> OpenDocumentAsync(string filePath, DocOptions? options = null, CancellationToken ct = default)Opening from disk with automatic format detection and the format's default config
Task<string> OpenDocumentAsync(string filePath, BaseConfig? config, DocOptions? options = null, CancellationToken ct = default)You need per-format rendering options (PdfConfig, WordConfig, …)
Task<string> OpenDocumentAsync(Stream stream, FileInfo fileInfo, BaseConfig? config = null, DocOptions? options = null, CancellationToken ct = default)The document isn't a file on disk (upload, database, blob). fileInfo must carry the correct extension — it drives format detection
csharp
// Simple open
string token = await viewer.OpenDocumentAsync(path);

// With per-format config and options
token = await viewer.OpenDocumentAsync(
    path,
    new PdfConfig { AllowSearch = true, AllowCopy = true },
    new DocOptions { TimeOut = 30 });

// From an upload
await using var ms = new MemoryStream();
await file.CopyToAsync(ms);
ms.Position = 0;
token = await viewer.OpenDocumentAsync(ms, new FileInfo(file.FileName));

Exceptions to handle:

  • LicenseException — a found license is rejected (the message carries the rejection reason), or the format needs a plugin capability that is no longer granted. Calendar expiry without a rejection message degrades to watermarked rendering instead of throwing.
  • FormatNotSupportedExceptionDocument format '<extension>' is not supported.
  • InvalidDataException — the file content is corrupt or doesn't match its extension.

CloseDocument

text
void CloseDocument(string token)

Removes the session from the cache (disposing the document engine immediately), deletes the security marker, and revokes the access grant. Optional — sliding expiration performs the same cleanup — but recommended for large documents.

GetPageCount

text
int GetPageCount(string token)

Total pages of the open session. Throws if the token is unknown or expired.

DocOptions

Per-open, format-independent options (namespace Doconut):

TypePropertyDefaultDescription
stringPassword""Password for protected documents (copied into the format config automatically).
intImageResolution0Obsolete. Kept for compatibility only — set ImageResolution on the format config instead.
stringWatermark""Custom watermark text drawn on rendered pages. Format string: "^Text~Color~FontSize~FontName~Opacity~Angle", e.g. "^Sample Copy~Red~24~Verdana~80~-45".
intTimeOut60Session sliding-expiration in minutes.
boolIsSecuredtrueNot currently enforced — reserved. Token binding is controlled globally by DoconutOptions.UnsafeMode (see Core Concepts → Sessions & Security).

The class also exposes specialized properties that are intentionally outside the normal single-host viewing flow:

TypePropertyDefaultDescription
boolIsWebFarmfalseMarks the open operation as a web-farm scenario. Use only with the corresponding shared storage/session architecture.
stringWebFarmPath""Shared path used by the specialized web-farm workflow. Empty in the normal single-host viewer.
boolEditModefalseReserved for the separately distributed Editor workflow; leave false for the standard viewer.

Custom watermark

DocOptions.Watermark uses six tilde-separated fields. An optional leading ^ requests the all-corners layout:

text
^Text~Color~FontSize~FontName~Opacity~Angle
csharp
string token = await viewer.OpenDocumentAsync(
    path,
    new PdfConfig(),
    new DocOptions
    {
        Watermark = "^Confidential~Red~24~Verdana~80~-45",
        TimeOut = 30
    });
FieldExampleMeaning
Leading ^^Optional all-corners layout. Without it, normal watermark placement is used.
TextConfidentialText rendered on each page. It must not be empty.
ColorRedNamed color understood by the drawing layer.
FontSize24Font size; invalid numeric input falls back to the renderer default.
FontNameVerdanaRequested font family. Ensure it is installed in the deployment environment.
Opacity80Byte value from 0 to 255. It must parse successfully.
Angle-45Rotation angle in degrees; invalid numeric input falls back to the default.

The parser expects exactly six fields after the optional ^. An invalid definition is replaced by the SDK's visible Invalid Watermark fallback instead of silently disappearing.

License decision

License stateCustom value suppliedRendered result
Valid paid viewer licenseNoClean page
Valid paid viewer licenseYesCustom watermark
Active Temporary/Demo base viewerNoClean base-viewer page
Active Temporary/Demo base viewerYesCustom watermark when the clean base-viewer path applies
Missing, rejected, expired, wrong-version, or invalid-domain licenseEitherEnforcement/evaluation watermark; the custom value does not override it
Plugin rendering under evaluation rulesEitherEvaluation watermark

The same decision is applied to served page images and annotation exports. Animated GIF output is stamped frame by frame. A custom watermark is therefore a licensed application feature, not a way to replace or suppress the evaluation watermark.

Annotations API

Server-side annotation loading and export. The full walkthrough lives in Guides → Annotations; the surface is:

MemberPurpose
AnnotationManager GetAnnotationManager(string token)Manager bound to the open session's page dimensions
AnnotationManager GetAnnotationManager(string token, int pageWidth, int pageHeight)Manager with explicit page dimensions
AnnotationManager GetAnnotationManager(int pageWidth, int pageHeight)Session-independent manager
void LoadAnnotationData(string token, AnnotationManager manager)Load annotations built in C# into the session
void LoadAnnotationData(string token, string annotationData)Load annotations from the encoded page/Base64 envelope returned by AnnotationManager.GetAnnotationData()
void LoadAnnotationXML(string token, XmlDocument annotationXml)Load annotations from XML
XmlDocument GetAnnotationXML(string token)Export the session's annotations as XML
Task<byte[]> ExportAnnotationsToPdfAsync(string token, int zoom = 100, CancellationToken ct = default)PDF with annotations burned in
Task<int> ExportAnnotationsToPngAsync(…)PNG files with annotations burned in
Task<byte[]> ExportAnnotationsToPngZipAsync(string token, int zoom = 100, CancellationToken ct = default)ZIP of per-page PNGs with annotations burned in

DICOM metadata

text
Task<DicomMetadata?> GetDicomMetadataAsync(string token, CancellationToken ct = default)

Returns DICOM tag metadata for sessions opened through the DICOM plugin; null for non-DICOM documents.

Resource helpers — ReferenceCss / ReferenceScripts

Emit the <link>/<script> tags for the embedded resources served by UseDoconutResources(), in correct dependency order. Bundles for license-gated features such as search and annotation are emitted only when the license enables them, keeping the client UI consistent with server behavior.

text
string ReferenceCss(CssConfig? config = null)      // null → Bootstrap + viewer + search + annotation
string ReferenceScripts(ScriptConfig? config = null)

CssConfig flags: IncludeBootstrapCss, IncludeViewerCss, IncludeSearchCss (search-gated), IncludeAnnotationCss (annotation-gated).

ScriptConfig flags: IncludeJQuery (required by all others), IncludeBootstrap, IncludeViewerScripts (core: docViewer.js + splitter + links), IncludeSearchScripts and IncludeSearchBar (search-gated), IncludeAnnotationScripts and IncludeAnnotationBar (annotation-gated).

html
@inject Doconut.Viewer Viewer

@Html.Raw(Viewer.ReferenceCss(new CssConfig { IncludeBootstrapCss = true, IncludeViewerCss = true }))
@Html.Raw(Viewer.ReferenceScripts(new ScriptConfig { IncludeJQuery = true, IncludeViewerScripts = true }))

Was this page helpful?