Szybki start

Renderuj swój pierwszy dokument w MVC 5 lub Web Forms

Ten przewodnik prowadzi aplikację ASP.NET na .NET Framework 4.7.2 od zainstalowanego pakietu do dokumentu renderowanego w przeglądarce: Global.asax, otwartego punktu końcowego, zasobów przeglądarki, widżetu oraz tokenu, który je łączy. Zakłada, że rejestracje Web.config z Installation są w miejscu — bez obsługi DocImage.axd i modułu zasobów, nic poniżej nie może dotrzeć do serwera.

Skonfiguruj Doconut w Global.asax

Pełny Application_Start dla aplikacji MVC 5:

csharp
// Global.asax.cs - twórz raz na proces roboczy, zwalniaj przy zamknięciu.
protected void Application_Start()
{
    Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

    Doconut.DoconutHost.Initialize(options =>
    {
        options.LicensePath = HostingEnvironment.MapPath("~/wwwroot/Doconut.Viewer.lic");
        options.UnsafeMode  = false; // strona jest dostarczana tylko sesji, która otworzyła dokument
    });

    // Tylko MVC: trzymaj dwa punkty końcowe Doconut poza routingiem.
    RouteTable.Routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    RouteTable.Routes.IgnoreRoute("doconut-res/{*pathInfo}");
}

protected void Application_End()
{
    Doconut.DoconutHost.Shutdown();
}
  • Encoding.RegisterProvider udostępnia procesowi starsze strony kodu, które niektóre formaty dokumentów wykorzystują. Wywołaj to raz, przed otwarciem pierwszego dokumentu.
  • UnsafeMode = false jest domyślną wartością, wypisaną, aby nikt nie zmienił jej przypadkowo: DocImage.axd serwuje stronę tylko do sesji ASP.NET, która otworzyła dokument.
  • Dwa wywołania IgnoreRoute utrzymują routing MVC z dala od DocImage.axd i /doconut-res/*, które obsługuje handler i moduł. Aplikacja Web Forms nie ma tras MVC i nie potrzebuje tej linii.
  • DoconutHost.Shutdown zatrzymuje pracę w tle Doconut i zwalnia jego usługi, gdy pula aplikacji jest recyklingowana. Bezpieczne jest wywołanie, nawet jeśli Initialize nigdy nie został uruchomiony.

Otwórz dokument

Otwarcie dokumentu zwraca nieprzezroczysty token. Widżet wysyła ten token przy każdym żądaniu strony.

W MVC 5 akcja kontrolera uzyskuje usługę Viewer z DoconutHost.Services — MVC 5 nie posiada wstrzykiwania przez konstruktor dla niej:

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

    // Token jest nieprzezroczysty - przekaż go do przeglądarki, nigdy nie loguj ani nie przechowuj go.
    string token = await viewer.OpenDocumentAsync(Server.MapPath("~/files/Sample.pdf"));
    return Json(new { token });
}

Dokument musi być otwarty w ramach żądania posiadającego stan sesji, ponieważ jego otwarcie przyznaje bieżącej sesji ASP.NET dostęp do jego stron. Kontrolery MVC i strony Web Forms mają stan sesji domyślnie. Niestandardowy IHttpHandler go nie posiada, chyba że implementuje System.Web.SessionState.IRequiresSessionState. Otwórz dokument z handlera bez tego, a przeglądarka wyświetli “You Are Not Authorized To View This Page.” na każdej stronie.

W Web Forms sama strona może otworzyć dokument w swoim kodzie zaplecza. OpenDocument jest synchroniczną formą OpenDocumentAsync, przeznaczoną dla kodu zaplecza, który nie używa stron asynchronicznych:

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"));
}

Traktuj token jak poświadczenie typu bearer: nigdy go nie loguj ani nie przechowuj; przekaż go wyłącznie widżetowi. Przestaje działać, gdy sesja dokumentu wygaśnie — otwórz dokument ponownie, aby uzyskać nowy.

Odniesienie do zasobów przeglądarki

Viewer.ReferenceCss i Viewer.ReferenceScripts emitują tagi <link> i <script> dla osadzonych zasobów, w kolejności zależności, wskazując na /doconut-res/. Widżet jest wtyczką jQuery, więc jQuery jest pierwszy.

MVC 5. Widoki nie mają @inject, więc generuj tagi w kontrolerze i przekaż je dalej ViewBag:

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)

Pozostaw tę pracę w kontrolerze. MVC 5 kompiluje widoki, gdy są po raz pierwszy serwowane, i bez dodatkowego pakietu kompilatora ten kompilator rozumie tylko C# 5 — brak ?., brak $"...", brak nameof. Widok, który ich używa, kompiluje się czysto w Visual Studio, a następnie zwraca pusty 500 w przeglądarce.

Web Forms. Udostępnij te same ciągi z kodu zaplecza i zapisz je przy użyciu <%= %>:

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

IncludeViewerCss i IncludeViewerScripts są obowiązkowym rdzeniem. Aby dodać wstążki Search i Annotation, ustaw także IncludeSearchCss, IncludeAnnotationCss, IncludeSearchScripts, IncludeSearchBar, IncludeAnnotationScripts i IncludeAnnotationBar. Obie metody pomijają pliki wstążki, gdy licencja nie przyznaje tej możliwości; sam przeglądarka nadal się uruchamia.

Dodaj przeglądarkę do strony

Powierzchnia renderowania to dwa zagnieżdżone div:

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

Nadaj zewnętrznemu div rzeczywistą wysokość — przeglądarka wypełnia swój kontener i mierzy go przy uruchomieniu. Przeglądarka nie rysuje własnego paska narzędzi: GotoPage, Next, Zoom, FitType, a pozostałe są metodami, które twoja strona podłącza do własnych przycisków, umieszczonych obok przeglądarki:

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>

Zainicjalizuj przeglądarkę i pokaż dokument

Po skryptach przeglądarki, utwórz widżet, a następnie przekaż mu token:

javascript
var objViewer = $('#div_ctlDoc').docViewer({
    showThumbs: true,
    autoLoad:   false,
    pageZoom:   100,
    FitType:    'width',
    BasePath:   '/',                   // '/' oznacza DocImage.axd w katalogu głównym witryny
    ResPath:    'doconut-res/images',  // bez wiodącego '/'
    onViewerReady: function () {
        // strony są widoczne; ukryj wskaźnik ładowania tutaj
    },
    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); });

W Web Forms, gdzie strona otworzyła dokument samodzielnie, ostatnie trzy linie stają się objViewer.View('<%= Token %>');.

Cztery szczegóły tutaj zawodzą bez komunikatu o błędzie:

  • BasePath: '/' adresuje DocImage.axd w korzeniu witryny. Dla aplikacji w wirtualnym katalogu, użyj jej nazwy bez ukośników ('myapp' żąda /myapp/DocImage.axd). Prowadzący ukośnik ('/myapp') generuje //myapp/DocImage.axd, które przeglądarka odczytuje jako żądanie do innego hosta.
  • ResPath: 'doconut-res/images' — ikony znajdują się jeden folder poniżej korzenia zasobów. Z 'doconut-res', każda ikona zwraca 404: brak glifów paska narzędzi i brak wskaźnika ładowania, podczas gdy sam dokument nadal się renderuje. Prowadzący ukośnik psuje to w ten sam sposób co BasePath.
  • Wywołania zwrotne są opcjami. onViewerReady, onError i pozostałe trafiają do obiektu przekazywanego do docViewer(...). Globalna funkcja nazwana po przeglądarce, taka jak ctlDoc_ViewerReady, nigdy nie jest wywoływana.
  • Zachowaj przeglądarkę, a następnie wywołaj View osobno. docViewer(...) zwraca obiekt z Zoom, Next i FitType; View(...) zwraca coś innego. var objViewer = $('#div_ctlDoc').docViewer({...}).View(token) renderuje dokument, a potem zawodzi z objViewer.Zoom is not a function przy pierwszym kliknięciu paska narzędzi.

Nazwy opcji mieszają camelCase (showThumbs, autoLoad, pageZoom) i PascalCase (FitType, BasePath, ResPath). Błędnie napisana opcja jest ignorowana, a widżet używa domyślnej.

Alternatywa w jednej linii

Dla strony, która potrzebuje jedynie wyświetlić dokument, bez własnego paska narzędzi, Viewer.RenderViewer zapisuje cały skrypt inicjalizacyjny — docViewer(...) z BasePath: '/' i ResPath: 'doconut-res/images', a następnie .View(token). Istnieje tylko w tym pakiecie:

csharp
// Kod zaplecza Web Forms, po otwarciu dokumentu
ViewerInit = viewer.RenderViewer("div_ctlDoc", Token);
html
<div id="div_ctlDoc" style="height: 100vh"></div>
<%= ViewerScripts %>
<%= ViewerInit %>

Przekaż ViewerConfig jako trzeci argument, aby zmienić powiększenie, dopasowanie lub panel miniatur. Ponieważ wygenerowany skrypt nie przechowuje odniesienia do przeglądarki dokumentu, użyj ręcznie napisanego inicjowania powyżej, gdy Twoja strona potrzebuje własnego paska narzędzi.

Zamknij dokument

Wywołaj objViewer.Close(true), gdy użytkownik opuszcza przeglądarkę dokumentu lub otwiera zamiennik: czyści widżet i wysyła żądanie zamknięcia do DocImage.axd. objViewer.Close() bez argumentu czyści tylko widżet. Na serwerze, viewer.CloseDocument(token) usuwa sesję dokumentu natychmiast, zwalnia jej zasoby renderujące i odbiera sesji dostęp do jej stron. Przesuwające się wygaśnięcie ostatecznie robi to samo, ale zamknięcie dużych dokumentów jawnie zwalnia pamięć szybciej.

Uruchom to

Umieść plik PDF w ~/files/Sample.pdf, uruchom witrynę w IIS Express (F5 w Visual Studio) i otwórz stronę, która hostuje widżet. Pierwsza strona jest renderowana, z miniaturkami po lewej. Jeśli tak się nie stanie, zobacz Rozwiązywanie problemów.

Co otrzymujesz bez licencji

Brak licencji nie powoduje błędu. Przeglądarka renderuje normalnie, ale każda strona zawiera znak wodny oceny. Zobacz Konfiguracja licencji, aby dowiedzieć się, gdzie Doconut szuka Twojej licencji.

Czy ta strona była pomocna?