Schnellstart

Rendern Sie Ihr erstes Dokument in MVC 5 oder Web Forms

Dieses Tutorial führt eine ASP.NET‑Anwendung auf .NET Framework 4.7.2 von einem installierten Paket zu einem im Browser gerenderten Dokument: Global.asax, einem offenen Endpunkt, den Assets des Viewers, dem Widget und dem Token, das sie verbindet. Es wird angenommen, dass die Web.config‑Registrierungen aus Installation vorhanden sind – ohne den DocImage.axd‑Handler und das Ressourcenmodul kann nichts Weiteres den Server erreichen.

Doconut in Global.asax zusammenstellen

Ein vollständiges Application_Start für eine MVC 5‑Anwendung:

csharp
// Global.asax.cs - einmal pro Worker-Prozess zusammenstellen, bei Herunterfahren freigeben.
protected void Application_Start()
{
    Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

    Doconut.DoconutHost.Initialize(options =>
    {
        options.LicensePath = HostingEnvironment.MapPath("~/wwwroot/Doconut.Viewer.lic");
        options.UnsafeMode  = false; // Eine Seite wird nur an die Sitzung ausgeliefert, die das Dokument geöffnet hat.
    });

    // Nur MVC: Halte die beiden Doconut-Endpunkte aus dem Routing heraus.
    RouteTable.Routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    RouteTable.Routes.IgnoreRoute("doconut-res/{*pathInfo}");
}

protected void Application_End()
{
    Doconut.DoconutHost.Shutdown();
}
  • Encoding.RegisterProvider macht die Legacy‑Code‑Seiten, die einige Dokumentformate verwenden, für den Prozess verfügbar. Rufen Sie es einmal auf, bevor das erste Dokument geöffnet wird.
  • UnsafeMode = false ist die Vorgabe, ausgeschrieben, damit niemand sie versehentlich ändert: DocImage.axd liefert eine Seite nur an die ASP.NET‑Sitzung, die das Dokument geöffnet hat.
  • Die beiden IgnoreRoute‑Aufrufe halten das MVC‑Routing von DocImage.axd und /doconut-res/* fern, die vom Handler und vom Modul bereitgestellt werden. Eine Web‑Forms‑Anwendung hat keine MVC‑Routen und benötigt diese Zeile nicht.
  • DoconutHost.Shutdown stoppt Doconut's Hintergrundarbeit und gibt seine Dienste frei, wenn der Anwendungspool recycelt wird. Es ist sicher, es aufzurufen, selbst wenn Initialize nie ausgeführt wurde.

Dokument öffnen

Das Öffnen eines Dokuments liefert ein undurchsichtiges Token. Das Widget sendet dieses Token mit jeder Seitenanfrage.

In MVC 5 löst eine Controller‑Aktion den Viewer‑Dienst aus DoconutHost.Services auf – MVC 5 unterstützt keine Konstruktorinjektion dafür:

csharp
// POST /Document/Open
[HttpPost]
public async Task<ActionResult> Open()
{
    var viewer = Doconut.DoconutHost.Services.GetRequiredService<Viewer>();

    // Das Token ist undurchsichtig - übergebe es dem Viewer, logge es niemals oder speichere es nicht.
    string token = await viewer.OpenDocumentAsync(Server.MapPath("~/files/Sample.pdf"));
    return Json(new { token });
}

Das Dokument muss innerhalb einer Anfrage geöffnet werden, die Session‑State hat, da das Öffnen dem aktuellen ASP.NET‑Session Zugriff auf seine Seiten gewährt. MVC‑Controller und Web‑Forms‑Seiten besitzen standardmäßig Session‑State. Ein benutzerdefinierter IHttpHandler hat keinen, es sei denn, er implementiert System.Web.SessionState.IRequiresSessionState. Öffnet man ein Dokument von einem Handler ohne ihn, zeigt der Viewer auf jeder Seite die Meldung „Sie sind nicht berechtigt, diese Seite anzuzeigen.“ an.

In Web Forms kann die Seite selbst das Dokument in ihrem Code‑Behind öffnen. OpenDocument ist die synchrone Form von OpenDocumentAsync, gedacht für Code‑Behind, das keine asynchronen Seiten verwendet:

csharp
// Default.aspx.cs
protected string Token;

protected void Page_Load(object sender, EventArgs e)
{
    var viewer = Doconut.DoconutHost.Services.GetRequiredService<Viewer>();
    Token = viewer.OpenDocument(Server.MapPath("~/files/Sample.pdf"));
}

Behandeln Sie das Token wie ein Berechtigungsnachweis: Loggen Sie es niemals und speichern Sie es nicht; geben Sie es nur an das Widget weiter. Es hört auf zu funktionieren, wenn die Dokumentsitzung abläuft – öffnen Sie das Dokument erneut, um ein neues zu erhalten.

Referenzieren der Viewer-Assets

Viewer.ReferenceCss und Viewer.ReferenceScripts erzeugen die <link> und <script> Tags für die eingebetteten Assets, in Abhängigkeitsreihenfolge, die auf /doconut-res/ verweisen. Das Widget ist ein jQuery‑Plugin, daher kommt jQuery zuerst.

MVC 5. Views haben kein @inject, also erzeugen Sie die Tags im Controller und geben sie an ViewBag weiter:

csharp
public ActionResult Index()
{
    var viewer = Doconut.DoconutHost.Services.GetRequiredService<Viewer>();
    ViewBag.ViewerCss = viewer.ReferenceCss(new CssConfig
    {
        IncludeBootstrapCss = true,
        IncludeViewerCss    = true
    });
    ViewBag.ViewerScripts = viewer.ReferenceScripts(new ScriptConfig
    {
        IncludeJQuery        = true,
        IncludeBootstrap     = true,
        IncludeViewerScripts = true
    });
    return View();
}
html
@Html.Raw(ViewBag.ViewerCss)
...
@Html.Raw(ViewBag.ViewerScripts)

Lassen Sie diese Arbeit im Controller. MVC 5 kompiliert Views, wenn sie das erste Mal ausgeliefert werden, und ohne ein zusätzliches Compiler‑Paket versteht dieser Compiler nur C# 5 — kein ?., kein $"...", kein nameof. Eine View, die sie verwendet, kompiliert sauber in Visual Studio und liefert dann ein leeres 500 im Browser.

Web Forms. Stellen Sie dieselben Zeichenketten aus dem Code‑Behind bereit und schreiben Sie sie mit <%= %>:

html
<head>
    <%= ViewerCss %>
</head>
<body>
    ...
    <%= ViewerScripts %>
</body>

IncludeViewerCss und IncludeViewerScripts sind der obligatorische Kern. Um die Such‑ und Annotations‑Bänder hinzuzufügen, setzen Sie außerdem IncludeSearchCss, IncludeAnnotationCss, IncludeSearchScripts, IncludeSearchBar, IncludeAnnotationScripts und IncludeAnnotationBar. Beide Methoden lassen die Dateien eines Bandes weg, wenn die Lizenz diese Fähigkeit nicht gewährt; der Viewer selbst startet jedoch.

Den Viewer zu einer Seite hinzufügen

Die Rendering‑Fläche besteht aus zwei verschachtelten divs:

html
<div id="divDocViewer">
    <div id="div_ctlDoc"></div>
</div>

Geben Sie dem äußeren div eine echte Höhe — der Viewer füllt seinen Container und misst ihn, wenn er startet. Der Viewer zeichnet seine eigene Symbolleiste nicht: GotoPage, Next, Zoom, FitType und der Rest sind Methoden, die Ihre Seite an ihre eigenen Schaltflächen bindet, neben dem Viewer platziert:

html
<nav id="toolbar" aria-label="Document viewer controls">
    <button type="button" onclick="objViewer.GotoPage(1)">First</button>
    <button type="button" onclick="objViewer.Next(false)">Previous</button>
    <button type="button" onclick="objViewer.Next(true)">Next</button>
    <button type="button" onclick="objViewer.Zoom(false)">Zoom out</button>
    <button type="button" onclick="objViewer.Zoom(true)">Zoom in</button>
    <button type="button" onclick="objViewer.FitType('width')">Fit width</button>
</nav>

Initialisieren des Viewers und Anzeigen des Dokuments

Nach den Viewer‑Skripten erstellen Sie das Widget und übergeben ihm dann das Token:

javascript
var objViewer = $('#div_ctlDoc').docViewer({
    showThumbs: true,
    autoLoad:   false,
    pageZoom:   100,
    FitType:    'width',
    BasePath:   '/',                   // '/' bedeutet DocImage.axd im Root der Seite
    ResPath:    'doconut-res/images',  // kein führendes '/'
    onViewerReady: function () {
        // Seiten sind sichtbar; hier einen Ladeindikator ausblenden
    },
    onError: function (message) {
        console.error('Doconut viewer error:', message);
    }
});

fetch('/Document/Open', { method: 'POST' })
    .then(function (resp) { return resp.json(); })
    .then(function (data) { objViewer.View(data.token); });

In Web Forms, wo die Seite das Dokument selbst öffnete, werden die letzten drei Zeilen zu objViewer.View('<%= Token %>');.

Vier Details hier schlagen fehl, ohne eine Fehlermeldung:

  • BasePath: '/' adressiert DocImage.axd an der Seitenwurzel. Für eine Anwendung in einem virtuellen Verzeichnis verwenden Sie dessen Namen ohne Schrägstriche ('myapp' fordert /myapp/DocImage.axd an). Ein führender Schrägstrich ('/myapp') erzeugt //myapp/DocImage.axd, das der Browser als Anfrage an einen anderen Host interpretiert.
  • ResPath: 'doconut-res/images' — die Symbole befinden sich einen Ordner unterhalb der Ressourcenwurzel. Mit 'doconut-res' liefert jedes Symbol 404 zurück: keine Symbolleisten‑Symbole und kein Ladespinner, während das Dokument selbst weiterhin gerendert wird. Ein führender Schrägstrich bricht es auf dieselbe Weise wie BasePath.
  • Callbacks sind Optionen. onViewerReady, onError und der Rest gehören in das Objekt, das an docViewer(...) übergeben wird. Eine globale Funktion, die nach dem Viewer benannt ist, wie ctlDoc_ViewerReady, wird niemals aufgerufen.
  • Behalten Sie den Viewer, dann rufen Sie View separat auf. docViewer(...) gibt das Objekt mit Zoom, Next und FitType zurück; View(...) gibt etwas anderes zurück. var objViewer = $('#div_ctlDoc').docViewer({...}).View(token) rendert das Dokument, schlägt dann beim ersten Klick auf die Symbolleiste mit objViewer.Zoom is not a function fehl.

Optionsnamen mischen camelCase (showThumbs, autoLoad, pageZoom) und PascalCase (FitType, BasePath, ResPath). Eine falsch geschriebene Option wird ignoriert, und das Widget verwendet den Standardwert.

Die einzeilige Alternative

Für eine Seite, die nur ein Dokument anzeigen muss, ohne eigene Symbolleiste, schreibt Viewer.RenderViewer das gesamte Initialisierungsskript — docViewer(...) mit BasePath: '/' und ResPath: 'doconut-res/images', dann .View(token). Es ist nur in diesem Paket enthalten:

csharp
// Web Forms code-behind, nach dem Öffnen des Dokuments
ViewerInit = viewer.RenderViewer("div_ctlDoc", Token);
html
<div id="div_ctlDoc" style="height: 100vh"></div>
<%= ViewerScripts %>
<%= ViewerInit %>

Übergeben Sie ein ViewerConfig als drittes Argument, um den Zoom, die Passform oder das Miniaturbild-Panel zu ändern. Da das erzeugte Skript keinen Verweis auf den Viewer enthält, verwenden Sie die oben handgeschriebene Initialisierung, wenn Ihre Seite eine eigene Symbolleiste benötigt.

Dokument schließen

Rufen Sie objViewer.Close(true) auf, wenn der Benutzer den Viewer verlässt oder einen Ersatz öffnet: Es löscht das Widget und sendet eine Schließanforderung an DocImage.axd. objViewer.Close() ohne Argument löscht nur das Widget. Auf dem Server entfernt viewer.CloseDocument(token) die Dokumentsitzung sofort, gibt deren Rendering‑Ressourcen frei und entzieht der Sitzung den Zugriff auf ihre Seiten. Das gleitende Ablaufdatum bewirkt schließlich dasselbe, aber das explizite Schließen großer Dokumente gibt den Speicher früher frei.

Ausführen

Legen Sie ein PDF unter ~/files/Sample.pdf ab, starten Sie die Website in IIS Express (F5 in Visual Studio) und öffnen Sie die Seite, die das Widget hostet. Die erste Seite wird gerendert, mit Miniaturansichten links. Wenn dies nicht geschieht, siehe Fehlerbehebung.

Was Sie ohne Lizenz erhalten

Eine fehlende Lizenz löst keinen Fehler aus. Der Viewer rendert normal, aber jede Seite trägt ein Evaluationswasserzeichen. Siehe Lizenzsetup für den Ort, an dem Doconut nach Ihrer Lizenz sucht.

War diese Seite hilfreich?