البدء السريع

عرض مستندك الأول في 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. عرّف السلاسل نفسها من الكود الخلفي واكتبها باستخدام <%= %>:

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.
  • الدوال الراجعة هي خيارات. 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 عن الترخيص الخاص بك.

هل كانت هذه الصفحة مفيدة؟