الترحيل إلى .NET Standard 2.1
نقل تطبيق Doconut.NETStandard الحالي من 26.7.0 إلى 26.8.0
Doconut لديها تكاملين مميزين لـ .NET Standard. يستخدمان نفس اسم الحزمة Doconut.NETStandard، لذا حدد الجيل من الإصدار وواجهات البرمجة في التطبيق قبل تغيير الحزم أو الإعدادات أو التراخيص أو موارد المتصفح.
الإصدار هو الفاصل في الطريق
كلا الجيلين ينشران تحت معرف الحزمة نفسه. فقط الإصدار يميزهما:
| الإصدار | الهدف | واجهة برمجة التطبيقات |
|---|---|---|
| 26.7.0 وما أدناه | netstandard2.0 | واجهة برمجة التطبيقات السابقة |
| 26.8.0 وما فوق | netstandard2.1 | واجهة برمجة التطبيقات الحالية |
رفع رقم الإصدار هو التحديث. لا توجد حزمة منفصلة للتثبيت ولا طبقة توافق — 26.8.0 هو سطح API مختلف. توقع أخطاء تجميع بعد الرفع؛ بقية هذا الدليل هي قائمة بهذه الأخطاء.
أي تكامل تستخدم؟
| إذا كان المشروع يحتوي على… | الجيل |
|---|---|
new Viewer(_cache, _accessor, ...) | السابقة |
viewer.OpenDocument(...) (متزامن) | السابقة |
viewer.InitCache() | السابقة |
UseDoconut(new DoconutOptions { ... }) | السابقة |
UseDoconutWebFarm(...) / WebFarmOptions | السابقة |
Viewer.DoconutLicense(...) أو Viewer.SetLicensePlugin(...) | السابقة |
viewer.Converter.GetConverter() | السابقة |
using Doconut.Configs; / using Doconut.Models; | السابقة |
نسخ يدوي لـ docViewer.js، documentLinks.js، أو docViewer.UI.js | السابقة |
builder.Services.AddDoconut(...) | الحالية |
app.UseDoconutResources() بالإضافة إلى app.UseDoconut() دون معاملات | الحالية |
Viewer المزوَّد بالحقن الاعتمادي | الحالية |
await viewer.OpenDocumentAsync(...) | الحالية |
إذا ظهرت كلا العمودين في نفس التطبيق، اعتبر الترحيل غير مكتمل. لا تُرسل رمز مستند واحد عبر الموارد أو الوسطاء من الجيل الآخر.
تحقق من إطار العمل المضيف أولاً
هذا باب صعب، ليس تفضيلًا. الحزمة الحالية تستهدف netstandard2.1:
| الإطار | يمكنه استهلاك 26.8.0 |
|---|---|
| .NET Core 3.0 أو أحدث (بما في ذلك .NET 5/6/7/8) | نعم |
| .NET Framework، أي نسخة | لا |
.NET Framework لا يمكنه الإشارة إلى مكتبة netstandard2.1. إذا كان التطبيق يعمل على .NET Framework، توقف هنا واستخدم حزمة Doconut.NETFramework بدلاً من ذلك؛ من الإصدار 26.9.0 تتطلب .NET Framework 4.7.2. كلا التطبيقين المرجعيين لهذا الإصدار يستهدفان net8.0.
قبل الترحيل
- إنشاء فرع ونسخة احتياطية قابلة للنشر من التطبيق الحالي.
- تسجيل إصدارات الحزمة الأساسية والإضافية بدقة.
- جرد كل استدعاء
new Viewer(...)، واستدعاءInitCache()، واستدعاء تحميل الترخيص، وتعيينUseDoconutWebFarm، ووحدة التحكم في التحويل، والسكريبت Doconut المنسوخ، وإجراء شريط الأدوات المخصص، واستدعاء رد الفعل للعارض، ونقطة النهاية لفتح المستند. - حافظ على ملفات
.licالحالية وأسرار النشر خارج نظام التحكم بالمصادر. - التقط مجموعة ممثلة من مستندات PDF، Office، الصور، CAD، البريد الإلكتروني، DICOM، القابلة للبحث، المحمية بكلمة مرور، والمُعَلَّمَة.
- سجل مهلة الجلسة الحالية، سلوك الأمان، الخطوط، وإعدادات المنصة.
قم بترحيل بيئة واحدة قبل تغيير الإنتاج. التكامل الحالي يغيّر عمر الخدمة، توجيه الطلبات، ملكية الجلسة، تسليم موارد العميل، — إذا كنت تدير مزرعة — كيفية وصول الصفحات إلى المتصفح.
1. المساحات الاسمية: تقريبًا كل شيء تم نقله إلى الجذر
أنواع الإعداد كانت موزعة عبر أربع مساحات اسمية. الآن جميعها في Doconut.
| قبل | الآن |
|---|---|
using Doconut.Configs.View; | using Doconut; |
using Doconut.Models; | using Doconut; |
using Doconut.Configs; | using Doconut; |
using Doconut.Configs.Cloud; | using Doconut.Clouds; |
using Doconut.Configs.Conversion; | دون تغيير |
using Doconut.Middleware; | دون تغيير |
لم تتغير أسماء الأنواع: WordConfig, PdfConfig, ExcelConfig, CssConfig, ScriptConfig, CloudUploadConfig, AzureConfig, CDNConfig, FileShareConfig والبقية لا تزال موجودة. في معظم الملفات، التعديل الكامل هو حذف سطرين using.
Doconut.Configs.Editor (BaseConfigEditor, PdfConfigEditor) تم إزالته ولا يوجد بديل له في هذه الحزمة. إذا كان تطبيقك يستخدم تلك الأنواع، خطط لهذا الجزء بشكل منفصل ولا تعتبره جزءًا من هذا الترحيل.
2. توافق الحزمة والترخيص
استبدل أو حدّث الحزمة الأساسية عمدًا؛ لا تعتمد على معرف الحزمة المتطابق لاختيار واجهة برمجة التطبيقات الجديدة. الأمر الافتراضي يثبت أحدث إصدار ثابت:
dotnet add package Doconut.NETStandardللحصول على ترحيل قابل لإعادة الإنتاج إلى الإصدار الذي تم تدقيقه في هذا الدليل، مرّر الإصدار كخيار منفصل:
dotnet add package Doconut.NETStandard --version 26.8.0احتفظ بكل مكوّن إضافي من Doconut بالإصدار نفسه كما في الحزمة الأساسية — Doconut.NETStandard.Converter و Doconut.NETStandard.Dicom. التكامل الحالي يحمل التراخيص مرة واحدة أثناء AddDoconut()، باستخدام أولوية التحميل التالية:
LicenseStream > LicenseContent > LicensePath > automatic discoveryيبحث الاكتشاف التلقائي عن ملف Doconut.Viewer.lic والملفات المصاحبة Doconut.Viewer.<Capability>.lic. الاستدعاءات الثابتة السابقة Viewer.DoconutLicense(...) و Viewer.SetLicensePlugin(...) لم تعد آلية بدء تشغيل حالية، ولا قائمة List<string> لمسارات الترخيص التي كان يقبلها المُنشئ القديم لـ Viewer. انقل الترخيص إلى DoconutOptions، واحتفظ بالملفات المصاحبة معًا عند استخدام الاكتشاف التلقائي، أعد تشغيل التطبيق بعد تغيير الترخيص، وتحقق من القدرات عبر IDoconutLicenseService.
لا تفترض أن وجود ترخيص مكوّن إضافي قديم يثبت الأحقية في بناء مكوّن إضافي حالي. اختبر Viewer و Search و Annotation و Converter و DICOM بشكل منفصل باستخدام القطع المصدّقة من الإصدار.
3. بدء التشغيل والحقن الاعتمادي
في السابق كان يتم إنشاء الـ viewer لكل طلب وتم تمرير الخيارات إلى الوسيط:
// التكامل السابق — للتمييز فقط؛ لا تقم بتجميع هذا ضد SDK الحالي.
var viewer = new Viewer(_cache, _accessor);
// …
appBranch.UseDoconut(new DoconutOptions { UnSafeMode = false, ShowDoconutInfo = false });التكامل الحالي يسجّل Doconut مرة واحدة ويتلقى Viewer من خلال الحقن الاعتمادي:
builder.Services.AddDoconut(options =>
{
options.UnsafeMode = false; // ملاحظة تغيير التهجئة: UnSafeMode → UnsafeMode
options.ShowDoconutInfo = false;
options.LicensePath = "Doconut.Viewer.lic";
});
builder.Services.AddDistributedMemoryCache(); // حالة الجلسة تحتاج إلى ذاكرة تخزين مؤقت (MVC/Razor Pages يضيفان واحدة بالفعل)
builder.Services.AddSession();
app.UseSession();
app.UseDoconutResources();
app.UseDoconut();Viewer هو خدمة مؤقتة. مدير جلسة المستند وذاكرة التخزين المؤقت الخاصة به يمتلكان حالة المستند ذات العمر الأطول، وليس نسخة Viewer المحقونة المحددة.
ثلاثة أشياء يجب نقلها:
new Viewer(cache, accessor)اختفت. احقنDoconut.Viewerفي المتحكم الخاص بك، أو استخدم@inject Doconut.Viewer Viewerفي عرض Razor.UseDoconutResources()يستبدل ربطًا يدويًاapp.UseMiddleware<EmbeddedResourceMiddleware>()، ويجب أن يُنفّذ قبل فرع المستند.UnSafeMode→UnsafeMode. إعادة تسمية حرف واحد سيكتشفها المترجم.
عند كون UnsafeMode false يتحقق SDK من صحة رمز الجلسة مقابل الطلب الأصلي، لذا يجب أن تظل AddSession() / UseSession() في خط الأنابيب، مع استدعاء UseSession() قبل الفرع.
الأساليب التي لم تعد موجودة
| قبل | الآن |
|---|---|
viewer.OpenDocument(path, config, options) | await viewer.OpenDocumentAsync(path, config, options) |
viewer.InitCache() | تم الإزالة — لا يوجد شيء لتسخينه يدويًا؛ احذف الاستدعاء وأي علم "هل قمت بالتهيئة بالفعل؟" حوله |
viewer.ExportToPng(sharedPath) | انظر §7 |
viewer.ExportToCloud(cloudConfig) | انظر §7 |
using var v = new Viewer(...); v.CloseDocument(t) | viewer.CloseDocument(token) على النسخة المحقونة |
4. وسائط البرامج وتوجيه الموارد
UseDoconut() الآن لا يأخذ أي معاملات. شكل فرع MapWhen نفسه لا يحتاج إلى تغيير — فقط الوسيط داخلها:
app.UseDoconutResources(); // BEFORE the branch
app.MapWhen(
ctx => ctx.Request.Path.Value?.EndsWith("DocImage.axd", StringComparison.OrdinalIgnoreCase) == true,
branch => branch.UseDoconut());في خط الأنابيب الحالي:
- استدعِ
UseSession()قبل Doconut بينما أمان الجلسة مفعّل؛ - استدعِ
UseDoconutResources()قبلUseDoconut()؛ - حافظ على توافق
ResourcesPath، عناوين URL للموارد المُولدة، وResPathللعميل؛ - حافظ على توافق الفرع الذي تُخرِّطه و
BasePathللعميل.
MiddlewarePath هو تكوين تم التحقق منه؛ لا ينشئ فرع ASP.NET Core بحد ذاته.
5. إنشاء المشاهد وعمره
احذف التخزين المؤقت المملوك للتطبيق لكائنات Viewer. لا يوجد شيء متبقٍ في Viewer يستحق الاحتفاظ به: لا يحمل أي حالة مستند، وتخزين الجلسة يملك كل ما يبقى بعد انتهاء الطلب. قم بحقنه في نقطة النهاية، صفحة Razor، المتحكم، أو خدمة تطبيق ذات نطاق محدد:
app.MapPost("/api/open", async (Viewer viewer) =>
{
var token = await viewer.OpenDocumentAsync("wwwroot/files/Sample.pdf");
return Results.Ok(new { token });
});الرمز المميز المعاد يحدد جلسة مستند على الخادم. اعتبره اعتمادًا من نوع حامل: لا تقم بتسجيله، ولا تخزنه، ولا تضعه في التحليلات.
6. فتح وإغلاق المستندات
استبدل OpenDocument(...) المتزامن بـ OpenDocumentAsync(...):
// التكامل الحالي: يتم الحصول على Viewer من DI وفتح المستند غير متزامن.
var token = await viewer.OpenDocumentAsync(path, new PdfConfig { AllowSearch = true });الإصدارات الحالية تقبل مسار ملف أو تدفق، تكوين تنسيق اختياري، DocOptions اختياري، ورمز إلغاء. أغلق جلسة الخادم صراحةً عندما لا يحتاج المتصفح إليها:
viewer.CloseDocument(token);احذف أي استدعاء لـ InitCache() والعلمية التي تحميه — لا يوجد شيء لتسخينه يدويًا. لا تعيد استخدام رمز مميز تم إنشاؤه بواسطة المكتبة السابقة بعد الانتقال: افتح كل مستند مرة أخرى عبر الواجهة البرمجية الحالية.
7. مزرعة الويب → موزعة: أكبر تغيير
UseDoconutWebFarm و WebFarmOptions لم يعودا موجودين. إذا كان تطبيقك يستدعيهما، فهذا القسم هو التحديث الخاص بك؛ إذا لم يكن كذلك، انتقل إلى الفقرة §8.
في السابق كان هناك برنامج وسيط واحد يقوم بكل شيء: يقدم الصور المسبقة التجسيد من مجلد مشترك، ويستطلع بينما كان عقدة أخرى لا تزال تكتبها.
// التكامل السابق — استدعاء واحد، تنسيق ضمني عبر نظام الملفات.
appBranch.UseDoconutWebFarm(new WebFarmOptions
{
Path = Path.Combine(env.WebRootPath, "webfarm"),
PageWaitTimeSeconds = 180,
StartWaitFromPage = 5,
});نفس المهمة الآن مقسمة إلى نصفين صريحين. جانب الكتابة — العقدة التي تفتح المستند تنشر مجموعة الأصول بالكامل (الصفحات، معلومات المستند، فهرس البحث، البيانات الوصفية) في المشاركة:
var result = await _publisher.PublishAsync( // DistributedDocumentPublisher، تم حقنه من DI
pathToFile,
new FileShareConfig
{
Location = CloudLocation.FileShare,
RootPath = @"\\fileserver\doconut", // نفس المجلد الذي تستخدمه اليوم
UsePerTokenSubfolders = true,
},
config,
documentOptions,
new DistributedDocumentPublishOptions
{
CleanUpStagingDirectory = true,
FirstPagePriority = true,
});
return Content(result.Token);جانب القراءة — أي عقدة تخدم من المشاركة:
app.MapWhen(
ctx => ctx.Request.Path.Value?.EndsWith("DocImage.axd", StringComparison.OrdinalIgnoreCase) == true,
branch => branch.UseDoconutCloud<FileShareCloudHandler>(options =>
{
options.Location = CloudLocation.FileShare;
options.CloudUploadConfig = /* the SAME FileShareConfig as above */;
}, "/"));| قبل | الآن |
|---|---|
WebFarmOptions.Path | FileShareConfig.RootPath |
PageWaitTimeSeconds / StartWaitFromPage | تم إزالته — تم استبداله بـ FirstPagePriority على جانب الكتابة بالإضافة إلى FileShareConfig.ReadReadyPollMs على جانب القراءة |
viewer.OpenDocument(...) then viewer.ExportToPng(share) | استدعاء واحد لـ PublishAsync(...) |
DocOptions.IsWebfarm / WebfarmPath | ما زال موجودًا، مكتوبًا IsWebFarm / WebFarmPath — لكنه غير مطلوب في مسار النشر |
بنيتك لا تتغير. وجه RootPath إلى نفس مشاركة UNC وكل عقدة تستمر في العمل كما تفعل اليوم. ما يتغير هو أن النشر أصبح عملية تستدعيها، بدلاً من أن يكون تأثيرًا جانبيًا للعرض.
يجب أن يتفق النصفان. إذا اختلف
RootPathأوUsePerTokenSubfoldersبين الناشر والمعالج، سيجيب العقدة الأخرى بـ 404. أنشئ التكوين في مساعد واحد واستدعِه من كلا الجانبين.
PageWaitTimeSeconds = 180 كان يعني "حجب حتى ثلاث دقائق على أمل ظهور الصفحة". الاستبدال صريح: مع FirstPagePriority = true، الصفحة الأولى يمكن خدمتها فورًا والصفحات اللاحقة تجيب HTTP 202 Accepted حتى تُكتب. المشاهد المدمج يعيد المحاولة تلقائيًا عندما يتم ضبط retryOn409. العميل الذي لا يعيد المحاولة سيظهر بلاطات مكسورة للصفحات التي لا تزال تُعرض.
التنظيم الكامل، بما في ذلك النشر الخلفي وتذاكر الوصول، موجود في النشر الموزع.
8. التحويل هو مكوّن إضافي، وهو أصغر بكثير
سجّل المكوّن الإضافي، ثم حقّن الواجهة DocumentConverter:
builder.Services.AddDoconut(o => o.AddPlugin<ConverterPlugin>());// التكامل السابق
var converter = viewer.Converter.GetConverter();
var config = new WordConfigConverter { TargetFormat = WordConfigConverter.EnTargetFormat.PDF };
var result = converter.Convert(stream, SourceFormatConverter.DOCX, config);
// التكامل الحالي
var result = await _converter.ConvertAsync(stream, ".docx", ConversionTarget.Pdf, null, ct);ما الذي يستبدله ذلك:
SourceFormatConverter— تم إزالته. مرّر امتداد الملف كسلسلة نصية، بما في ذلك النقطة.- أنواع
*ConfigConverterالخاصة بكل عائلة (WordConfigConverter،ExcelConfigConverter، …)، كل منها يحتوي على تعدادEnTargetFormatمتداخل — تم إزالته. الآن يوجد تعداد واحدConversionTargetلكل عائلة. viewer.Converter.GetConverter()— تم إزالته. حقّنDoconut.DocumentConverter.
ConvertAsync تُعيد تدفقًا قابلًا للتمرير، لذا فإن return File(result, mime, name) يعمل مباشرة — نسخ MemoryStream التي كان يحتاجها الكود القديم ليست ضرورية. في العينة المرفقة، أدى ذلك إلى حذف تحويل امتداد يضم 68 حالة وعشرة وحدات تحكم متشابهة تقريبًا.
انظر إلى Converter Plugin للحصول على السطح الكامل.
9. مزودي السحابة
UseDoconutCloud أصبحت عامة. الموفر هو نوع الوسيط بدلاً من قيمة Location التي يتم التبديل بناءً عليها داخل الوسيط:
// التكامل السابق
appBranch.UseDoconutCloud(new CloudOptions { Location = CloudLocation.CDN, ... });
// التكامل الحالي
branch.UseDoconutCloud<CDNCloudHandler>(options =>
{
options.Location = CloudLocation.CDN;
options.CloudUploadConfig = new CDNConfig { DoconutCdnUrl = "..." };
}, "/");فئات التكوين لم تتغير باستثناء مساحة الاسم (Doconut.Configs.Cloud → Doconut.Clouds): AzureConfig، AmazonConfig، GoogleCloudConfig، DropBoxConfig، RedisConfig، CDNConfig، FTPConfig، بالإضافة إلى FileShareConfig الجديد. المعالجات تُسمى <Provider>CloudHandler.
معالج CDN هو للقراءة فقط — فهو يقدم ما هو موجود بالفعل على CDN؛ ولا يقوم بالرفع.
10. كائنات التكوين التي تغيرت أسماؤها
| قبل | الآن |
|---|---|
DoconutOptions.UnSafeMode | UnsafeMode |
DocOptions.IsWebfarm | IsWebFarm |
DocOptions.WebfarmPath | WebFarmPath |
DocOptions.ImageResolution | ما زال موجودًا لكن مهمل — اضبط الدقة في تكوين الصيغة بدلاً من ذلك |
DocOptions يضيف أيضًا IsSecured.
واجهة برمجة التطبيقات الحالية تفصل القضايا بشكل أكثر صرامة من السابقة، لذا تحقق من أن كل إعداد موجود في الكائن الذي يملكه الآن:
| القضية | النوع الحالي |
|---|---|
| مسارات الوسيط، الترخيص، تسجيل المكوّن الإضافي | DoconutOptions |
| كلمة المرور، مهلة الانتظار، الأمان، العلامة المائية | DocOptions |
| عرض الصيغة و DPI | PdfConfig، WordConfig، ExcelConfig، وغيرها من أنواع BaseConfig |
| الإعدادات الافتراضية لأداة المتصفح | ViewerConfig أو خيارات JavaScript المكافئة |
| CSS والسكريبتات المولدة | CssConfig و ScriptConfig |
| التخزين المشترك ومزودي السحابة | FileShareConfig وغيرها من تكوينات Doconut.Clouds |
لا تُستمر في استخدام DocOptions.ImageResolution كتحكم في العرض. فهو مهمل؛ اضبط BaseConfig.ImageResolution في تكوين الصيغة المحددة. راجع جميع الإعدادات الافتراضية بدلاً من افتراض أن التكوين السابق له نفس السلوك.
11. عارض الجانب العميل — تغييران يفشلان بصمت
كلاهما يترك الخادم يعمل بشكل كامل. مستندك يُعرض، والصفحة تبدو صحيحة، ولا يظهر شيء في وحدة تحكم المتصفح. اقرأ هذا القسم حتى لو نجح تجميع C# من أول محاولة.
ردود نداء العارض أصبحت خيارات الآن، وليس دوالًا عامة
العارض السابق كان يستدعي المعالجات الخاصة بك بالاسم، مستخرجًا اسم الدالة العامة من معرف الحاوية. كان تعريف function ctlDoc_OnViewerReady() في صفحة تحتوي على <div id="div_ctlDoc"> كافيًا. العارض الحالي يأخذ ردود نداء صريحة في كائن الخيارات ولم يعد يبحث عن تلك الدوال العامة:
objctlDoc = $("#div_ctlDoc").docViewer({
// ... خياراتك الحالية ...
onViewerBusy: ctlDoc_OnViewerBusy, // كان يُعثر عليه بالاسم
onViewerReady: ctlDoc_OnViewerReady, // كان يُعثر عليه بالاسم
onCopy: ctlDoc_Copy, // كان ctlDoc_Copy(text)
onAutoLoadStatus: ctlDoc_AutoLoadStatus // كان ctlDoc_AutoLoadStatus(page)
});لماذا هذا سيء: كان الاستدعاء القديم محاطًا بـ catch فارغ، مما ابتلع كل شيء. الآن لا تُنفّذ دوالك أبداً ولا يُبلغ عن أي خطأ. العَرَض الشائع هو مؤشر تحميل مستمر لا يتوقف — لأن الدالة التي كانت تخفيه هي ctlDoc_OnViewerReady. المستند خلفه سليم.
قائمة الخيارات الكاملة هي onPageLoading، onPageLoaded، onThumbnailClicked، onPageClicked، onDoubleClick، onViewerBusy، onViewerReady، onViewerError، onCopy، onAnnSaved، onAnnSaveError، onAnnLoaded، onAnnClosed، onAutoLoadStatus، onThumbsShown، و onError. لا يوجد رد نداء للنقر على الروابط: معالجة الروابط مدمجة وتُدار بواسطة showHyperlinks.
يجب أن يشير ResPath إلى بادئة المورد
ResPath: '', // قبل — الموارد كانت تأتي من جذر التطبيق
ResPath: 'doconut-res/images', // الآن — البادئة التي يركّبها UseDoconutResources()إذا قمت بتغيير البادئة عبر DoconutOptions.ResourcesPath، استخدم تلك القيمة بدلاً من ذلك.
12. شريط أدوات العارض، البحث، والتعليقات التوضيحية
لا تقم بترحيل السكريبتات القديمة واحدةً تلو الأخرى. التطبيقات المرجعية الحالية تُنشئ حزمة صفحة كاملة واحدة:
- إصدار CSS للعارض وCSS المرخص للبحث/التعليقات التوضيحية باستخدام
ReferenceCss؛ - عرض شريط أدوات العارض المملوك للتطبيق؛
- عرض
searchBarMount،annBarMount، والتركيب المطلوب للعارض؛ - إصدار سكريبتات العارض والوحدات المرخصة باستخدام
ReferenceScripts؛ - تحميل سكريبت المساعد الخاص بشريط أدوات التطبيق؛
- تهيئة كائن
objViewerواحد؛ - تهيئة أشرطة البحث والتعليقات التوضيحية المرخصة؛
- استدعاء
attach(objViewer)على كل شريط؛ - فتح المستند واستدعاء
objViewer.View(token).
البحث والتعليقات التوضيحية هما وحدتان مرفقتان بنفس العارض، وليسا شريطين أدوات مستقلين. شريط الأدوات الرئيسي يخص تطبيق المضيف؛ أشرطة البحث والتعليقات التوضيحية مدمجة، وتُقيد بالقدرات.
احذف الملفات المنسوخة يدويًا مثل documentLinks.js و docViewer.UI.js فقط بعد أن تعمل الصفحة الحالية مع الموارد الصادرة عن ReferenceCss و ReferenceScripts.
13. تسجيل الإضافات
طرق الترخيص الثابتة للإضافات لا تسجل الإضافات الحالية. قم بتثبيت وتسجيل كل حزمة مُصدرة صراحةً:
builder.Services.AddDoconut(options =>
{
options.AddPlugin<Doconut.Plugins.Converter.ConverterPlugin>();
options.AddPlugin<Doconut.Plugins.Dicom.DicomPlugin>();
});AddDoconut() يتحقق من قدرات الإضافات المسجلة عند بدء التشغيل. Converter و DICOM هما الإضافات الصادرة لـ .NET Standard. البحث والتعليقات التوضيحية العادية هي ميزات مرخصة مدمجة، ليست حزم AddPlugin<TPlugin>().
14. أمان الجلسة والوثيقة
التكامل الحالي يربط المستندات برموز غير شفافة وجلسات مخزنة مؤقتًا. مع الإعداد الافتراضي UnsafeMode = false، يضيف UseDoconut() أمان وصول المستند ويجب على المضيف تكوين جلسة ASP.NET:
builder.Services.AddDistributedMemoryCache(); // حالة الجلسة تحتاج إلى ذاكرة مخبأة (MVC/Razor Pages يضيفان واحدة بالفعل)
builder.Services.AddSession();
app.UseSession();احتفظ بـ DocOptions.IsSecured = true ما لم يتطلب تصميم مُراجَع خلاف ذلك. لا تستخدم أبداً UnsafeMode = true كاختصار للترحيل على عقدة واحدة. اختبر الطلبات بدون رمز، رمز غير صالح، رمز منتهي الصلاحية، ورمز من جلسة متصفح مختلفة.
في بيئة موزعة قد يصل طلب الصفحة إلى عقدة لم تشهد الطلب الأول، وبالتالي سيتسبب فحص الجلسة في رفضه. هذه هي الحالة الوحيدة التي يكون فيها UnsafeMode = true صحيحًا — ويجب أن يُقترن بتذاكر وصول موقعة عبر AddDoconutDistributedDocumentSecurity، وليس منفردًا. راجع النشر الموزع.
ملاحظة حول التسمية
في جميع الأطر، الصنف هو Viewer. إذا وجدت DocumentViewer في مقتطفات قديمة أو مقالات من طرف ثالث، فهذا النوع لم يكن موجودًا أبدًا في مجموعة تطوير البرمجيات (SDK).
15. ترتيب العمل المقترح
- تأكد من أن إطار العمل المضيف يمكنه استهلاك netstandard2.1. إذا لم يستطع، توقف.
- قم بترقية الحزمة إلى 26.8.0 ثم ابنِ المشروع. عالج أخطاء التجميع — معظمها أسطر
usingفي الفقرة §1. - انقل بدء التشغيل إلى
AddDoconut()واستدعاءات الطبقة الوسطية إلى ترتيبها الجديد (§3, §4). - حقن
Viewerحيث كنت تُنشئه، اجعلOpenDocumentغير متزامن، واحذفInitCache()(§5, §6). - إذا كنت تستخدم بيئة الويب الموزعة، نفّذ §7 — الجزء الوحيد الذي يتطلب إعادة تصميم وليس مجرد إعادة تسمية.
- إذا كنت تُحوّل المستندات، نفّذ §8.
- نفّذ §11 — التغييرات على جانب العميل. هي التي لن تُعلن عن نفسها.
- افتح مستندًا حقيقيًا في المتصفح، وراقب المؤشر المتحرك. بناء أخضر لا يثبت شيئًا هنا: الترخيص، تسجيل الإضافات، مسار المورد، واستدعاءات العارض جميعها تفشل فقط أثناء التشغيل. بالنسبة لبيئة موزعة، تحقق من أن مستندًا نُشر من عقدة واحدة يُقدَّم من عقدة أخرى.
اختبار الترحيل
على الأقل، تحقق من:
- بدء تشغيل التطبيق مع ترخيص الإنتاج وكل المكوّن الإضافي المسجّل؛
- ملفات CSS/السكريبتات الخاصة بالمُشاهد وجميع طلبات صور الصفحات تحت المسارات المختارة؛
- فتح المستند، التنقل، التكبير، المصغرات، الطباعة، والإغلاق الصريح؛
- البحث في مستند يحتوي على نص وحالة عدم إمكانية البحث في ملف يحتوي على صور فقط؛
- تحميل التعليقات التوضيحية، الحفظ، التصدير، وتقييد القدرة؛
- اكتشاف هدف المحول، الإخراج، التحميل، وحالة العلامة المائية؛
- صفحات DICOM، الإطارات، والرسوم المتحركة؛ البيانات الوصفية التقنية غير متوفرة في هذه الحزمة؛
- المستندات المحمية بكلمة مرور، الخطوط المخصّصة، النص غير اللاتيني، والمهلات المكوّنة؛
- رفض الرموز عبر الجلسات وسلوك الجلسة المنتهية؛
- في حالة مجموعة خوادم: نشر على عقدة واحدة، طلب صفحة متأخرة من أخرى، وتأكيد أن المُشاهد يعيد المحاولة عند استجابة
202بدلاً من عرض قطع مكسورة؛ - الهواتف المحمولة، الوضع الداكن، ومسار الوكيل العكسي للإنتاج.
خطة الاسترجاع
احتفظ بقطعة النشر السابقة، الحزم المطابقة، ملفات الترخيص، والموارد المتصفح المنسوخة معًا. عملية استرجاع آمنة تقوم بتبديل جيل التطبيق بالكامل؛ ولا تمزج خادمًا من الجيل السابق مع السكريبتات الحالية، أو خادمًا حاليًا مع مواقع استدعاء new Viewer(...).
قبل التحويل، وثّق:
- فتحة النشر أو القطعة المستخدمة للاسترجاع؛
- تأثير التخزين المشترك، إن وجد — القطع التي نشرت بواسطة 26.8.0 لا تُستهلك من قبل طبقة الوسط السابقة لمجموعة الويب؛
- كيفية إبطال جلسات المستند النشطة؛
- فحص الصحة ووثيقة الاختبار السريعة المستخدمة لتحديد الاسترجاع؛
- من يمكنه استعادة مجموعة الحزم السابقة والإعدادات.
الوثائق القديمة
الدليل السابق المترجم لا يزال متاحًا على إعداد .NET Standard القديم. يشرح بوابة التكامل السابقة نفس إشارات التعريف ويربط مرة أخرى إلى دليل الترحيل هذا.
احتفظ بالرابط التاريخي في الإشارات المرجعية وتذاكر الدعم طالما أن تثبيتات netstandard2.0 لا تزال موجودة. فهو يوثّق جيلًا مختلفًا ولا يتم توجيهه إلى واجهة برمجة التطبيقات الحالية.
هل كانت هذه الصفحة مفيدة؟