شروع سریع

رندر اولین سند خود در 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 - compose once per worker process, release on shutdown.
protected void Application_Start()
{
    Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

    Doconut.DoconutHost.Initialize(options =>
    {
        options.LicensePath = HostingEnvironment.MapPath("~/wwwroot/Doconut.Viewer.lic");
        options.UnsafeMode  = false; // a page is served only to the session that opened the document
    });

    // MVC only: keep the two Doconut endpoints out of routing.
    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، یک اکشن کنترلر سرویس Viewer را از DoconutHost.Services دریافت می‌کند — MVC 5 برای آن تزریق سازنده ندارد:

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

    // The token is opaque - hand it to the viewer, never log or persist it.
    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. رشته‌های مشابه را از کد‑پشت (code‑behind) در دسترس قرار دهید و با <%= %> بنویسید:

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:   '/',                   // '/' means DocImage.axd at the site root
    ResPath:    'doconut-res/images',  // no leading '/'
    onViewerReady: function () {
        // pages are visible; hide a loading indicator here
    },
    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 آن را خراب می‌کند.
  • Callbackها گزینه‌ها هستند. 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 code-behind, after opening the document
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 به دنبال لایسنس شما می‌گردد، به بخش راه‌اندازی لایسنس مراجعه کنید.

آیا این صفحه مفید بود؟