התחלה מהירה

הצגת המסמך הראשון שלך ב-MVC 5 או Web Forms

מדריך זה לוקח יישום ASP.NET על .NET Framework 4.7.2 מחבילה מותקנת למסמך שמוצג בדפדפן: Global.asax, נקודת קצה פתוחה, המשאבים של הצופה, הווידג'ט, והטוקן שמקשר ביניהם. הוא מניח שהרישומים של Web.config מ-התקנה קיימים — ללא המטפל DocImage.axd ומודול המשאבים, שום דבר למטה לא יוכל להגיע לשרת.

הרכבת Doconut ב-Global.asax

דוגמה מלאה של Application_Start ליישום MVC 5:

csharp
// Global.asax.cs - הרכבה פעם אחת לכל תהליך עובד, שחרור בעת כיבוי.
protected void Application_Start()
{
    Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

    Doconut.DoconutHost.Initialize(options =>
    {
        options.LicensePath = HostingEnvironment.MapPath("~/wwwroot/Doconut.Viewer.lic");
        options.UnsafeMode  = false; // דף מוגש רק לסשן שפתח את המסמך
    });

    // רק MVC: שמור את שני קצות Doconut מחוץ לניתוב.
    RouteTable.Routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    RouteTable.Routes.IgnoreRoute("doconut-res/{*pathInfo}");
}

protected void Application_End()
{
    Doconut.DoconutHost.Shutdown();
}
  • Encoding.RegisterProvider מאפשר את דפי קוד המורשת שבהם משתמשים כמה פורמטים של מסמכים להיות זמינים לתהליך. יש לקרוא לו פעם אחת, לפני פתיחת המסמך הראשון.
  • UnsafeMode = false הוא ברירת המחדל, כתוב במפורש כדי שמישהו לא ישנה אותו בטעות: DocImage.axd מגיש דף רק למפגש ASP.NET שפתח את המסמך.
  • שני הקריאות של IgnoreRoute שומרות על ניתוב MVC רחוק מ-DocImage.axd ו-/doconut-res/*, שאליהם המטפל והמודול מגישים. ליישום Web Forms אין נתיבי MVC ולכן אינו זקוק לשורה זו.
  • DoconutHost.Shutdown מפסיק את העבודה ברקע של Doconut ומשחרר את השירותים שלו כאשר מאגר היישומים מתחדש. ניתן לקרוא לו בבטחה גם אם Initialize מעולם לא רץ.

פתיחת מסמך

פתיחת מסמך מחזירה טוקן אטום. הווידג'ט שולח את הטוקן עם כל בקשת דף.

ב-MVC 5, פעולה של בקרת (controller) משיגה את השירות Viewer מ-DoconutHost.Services — ל-MVC 5 אין הזרקת בנאי עבורו:

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

    // הטוקן הוא בלתי שקוף - העבר אותו לצופה, לעולם אל תתעד או תשמר אותו.
    string token = await viewer.OpenDocumentAsync(Server.MapPath("~/files/Sample.pdf"));
    return Json(new { token });
}

המסמך חייב להיפתח בתוך בקשה שיש לה מצב סשן, מכיוון שהפתיחה היא מה שמעניקה למפגש ASP.NET הנוכחי גישה לדפים שלו. בקרי MVC ודפי Web Forms כוללים מצב סשן כברירת מחדל. IHttpHandler מותאם אישית אינו עושה זאת, אלא אם הוא מיישם System.Web.SessionState.IRequiresSessionState. פתיחת מסמך ממטפל ללא זה תגרום לצופה להציג "אינך מורשה לצפות בדף זה." בכל דף.

ב-Web Forms, העמוד עצמו יכול לפתוח את המסמך בקוד‑בייק שלו. OpenDocument היא הצורה הסינכרונית של OpenDocumentAsync, מיועדת לקוד‑בייק שאינו משתמש בדפים אסינכרוניים:

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

התייחס לטוקן כלאישור נושא: אל תתעד אותו או תשמר אותו; העבר אותו רק לווידג'ט. הוא מפסיק לעבוד כאשר סשן המסמך פג — פתח את המסמך שוב כדי לקבל טוקן חדש.

התייחס למקורות הצופה

Viewer.ReferenceCss וViewer.ReferenceScripts מפיקים את תגי <link> ו<script> עבור המשאבים המוטמעים, בסדר תלות, ופונים אל /doconut-res/. הווידג'ט הוא תוסף jQuery, ולכן jQuery מגיע ראשון.

MVC 5. לתצוגות אין @inject, ולכן יש לייצר את התגים בבקר ולהעביר אותם ב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)

השאר עבודה זו בבקר. MVC 5 מקמפל תצוגות כאשר הן מוגשות לראשונה, וללא חבילת קומפיילר נוספת הקומפיילר מבין רק C# 5 — ללא ?., ללא $"...", ללא nameof. תצוגה שמשתמשת בהם מקמפלת בצורה נקייה ב-Visual Studio, ואז מחזירה 500 ריק בדפדפן.

Web Forms. חשוף את המחרוזות זהות מהקוד-מאחורי וכתוב אותן עם <%= %>:

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

IncludeViewerCss וIncludeViewerScripts הם הליבה המחויבת. כדי להוסיף את רצועות החיפוש וההערה, יש גם להגדיר את IncludeSearchCss, IncludeAnnotationCss, IncludeSearchScripts, IncludeSearchBar, IncludeAnnotationScripts וIncludeAnnotationBar. שני השיטות משאירות קבצי רצועה כאשר הרישיון אינו מאפשר זאת; הצופה עצמו עדיין מתחיל.

הוסף את הצופה לעמוד

משטח הרינדור הוא שני divים מקוננים:

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

תן לdiv החיצוני גובה אמיתי — הצופה ממלא את המכולה שלו ומודד אותה כאשר הוא מתחיל. הצופה אינו מצייר את סרגל הכלים שלו: GotoPage, Next, Zoom, FitType והיתר הם שיטות שהדף שלך מחבר לכפתורים שלו, הממוקמים לצד הצופה:

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>

אתחל את הצופה והצג את המסמך

לאחר סקריפטי הצופה, צור את הווידג'ט, ואז העבר לו את האסימון:

javascript
var objViewer = $('#div_ctlDoc').docViewer({
    showThumbs: true,
    autoLoad:   false,
    pageZoom:   100,
    FitType:    'width',
    BasePath:   '/',                   // '/' משמעותו DocImage.axd בשורש האתר
    ResPath:    'doconut-res/images',  // אין '/' מוביל
    onViewerReady: function () {
        // הדפים נראים; הסתר אינדיקטור טעינה כאן
    },
    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); });

ב-Web Forms, כאשר העמוד פותח את המסמך בעצמו, שלוש השורות האחרונות הופכות לobjViewer.View('<%= Token %>');.

ארבעה פרטים כאן נכשלים ללא הודעת שגיאה:

  • BasePath: '/' מתייחס לDocImage.axd בשורש האתר. עבור אפליקציה בתיקייה וירטואלית, השתמש בשם שלה ללא קווים נטויים ('myapp' מבקש /myapp/DocImage.axd). קו נטוי מוביל ('/myapp') מייצר //myapp/DocImage.axd, שהדפדפן קורא כבקשה למארח אחר.
  • ResPath: 'doconut-res/images' — האייקונים ממוקמים תיקייה אחת מתחת לשורש המשאבים. עם 'doconut-res', כל אייקון מחזיר 404: אין סמלי סרגל כלים ואין ספינר טעינה, בעוד שהמסמך עצמו עדיין מוצג. קו נטוי מוביל שוב משבית זאת כמו BasePath.
  • החזרות (Callbacks) הן אפשרויות. onViewerReady, onError והיתר נכנסים לאובייקט המועבר לdocViewer(...). פונקציה גלובלית בשם הצופה, כגון ctlDoc_ViewerReady, לעולם לא נקראת.
  • שמור את הצופה, ואז קרא לView בנפרד. docViewer(...) מחזיר את האובייקט עם Zoom, Next וFitType; View(...) מחזיר משהו אחר. var objViewer = $('#div_ctlDoc').docViewer({...}).View(token) מציג את המסמך, ואז נכשל עם objViewer.Zoom is not a function בלחיצה הראשונה על סרגל הכלים.

שמות האפשרויות משולבים camelCase (showThumbs, autoLoad, pageZoom) ו-PascalCase (FitType, BasePath, ResPath). אפשרות עם שגיאת כתיב מתעלמים ממנה, והווידג'ט משתמש בערך ברירת המחדל שלו.

החלופה בשורה אחת

לדף שצריך רק להציג מסמך, ללא סרגל כלים משלך, Viewer.RenderViewer כותב את כל סקריפט האתחול — docViewer(...) עם BasePath: '/' ו-ResPath: 'doconut-res/images', ואז .View(token). הוא קיים רק בחבילה זו:

csharp
// קוד‑מאחורי של Web Forms, לאחר פתיחת המסמך
ViewerInit = viewer.RenderViewer("div_ctlDoc", Token);
html
<div id="div_ctlDoc" style="height: 100vh"></div>
<%= ViewerScripts %>
<%= ViewerInit %>

העבר את ViewerConfig כארגומנט שלישי כדי לשנות את תקריב התצוגה, את ההתאמה, או את לוח התמונות הממוזערות. מכיוון שהסקריפט שנוצר אינו שומר הפנייה לצופה, השתמש באתחול הידני שמופיע למעלה כאשר הדף שלך זקוק לסרגל כלים משלו.

סגירת המסמך

הפעל את objViewer.Close(true) כאשר המשתמש עוזב את הצופה או פותח חלופה: הוא מנקה את הווידג'ט ושולח בקשת סגירה ל-DocImage.axd. objViewer.Close() ללא ארגומנט מנקה רק את הווידג'ט. בשרת, viewer.CloseDocument(token) מסיר את מושב המסמך מיידית, משחרר את משאבי הרינדור שלו, ומסיר את הגישה של המושב לעמודים שלו. תפוגה מתגלגלת עושה זאת בסופו של דבר, אך סגירת מסמכים גדולים במפורש משחררת זיכרון מהר יותר.

הפעל אותו

הציב קובץ PDF ב-~/files/Sample.pdf, הפעל את האתר ב‑IIS Express (F5 ב‑Visual Studio), ופתח את הדף שמארח את הווידג'ט. העמוד הראשון מציג, עם תמונות ממוזערות משמאל. אם זה לא קורה, ראה פתרון בעיות.

מה שאתה מקבל ללא רישיון

חוסר רישיון אינו גורם לשגיאה. הצופה מציג כרגיל, אך כל עמוד נושא סימן מים של הערכה. ראה הגדרת רישיון כדי לדעת היכן Doconut מחפש את הרישיון שלך.

האם דף זה היה מועיל?