ملحق التحويل

تحويل المستندات إلى 24 صيغة مستهدفة

ملحق Converter يحول Doconut إلى خدمة تحويل مستندات. يضيف المحرك وراء الواجهة العامة DocumentConverter — وبالإضافة إلى ذلك — عنصر واجهة يمكن دمجه يُقدَّم عبر DocImage.axd، بحيث يمكنك تحويل المستندات من C#، أو من العنصر، أو من الواجهة الأمامية التي تبنيها بنفسك.

تثبيت الحزمة

powershell
Install-Package Doconut.NETFramework.Converter

احتفظ بحزمة Converter بنفس نسخة Doconut.NETFramework.

تسجيل الملحق

كل ملحق يُسجَّل بنفس الطريقة: AddPlugin<TPlugin>() داخل DoconutHost.Initialize.

csharp
Doconut.DoconutHost.Initialize(options =>
{
    options.LicensePath = HostingEnvironment.MapPath("~/wwwroot/Doconut.Viewer.lic");
    options.AddPlugin<Doconut.Plugins.Converter.ConverterPlugin>();
});

إذا لم تمنح أي رخصة سارية قدرة Converter — لا رخصة، أو ملف TRIAL قديم، أو رخصة بدون هذه القدرة — فإن DoconutHost.Initialize يطرح استثناءً من Application_Start. في System.Web يعني ذلك أن كل طلب يرد بـ 500 فارغ، والسبب يظهر فقط في سجل أحداث Windows (المصدر ASP.NET). تُقبل تراخيص Demo/NFR المؤقتة. راجع إعداد الترخيص.

التحويل من C#

كل عملية تحويل تُعيد MemoryStream قابل للبحث ومُحدَّد على الموضع 0. DocumentConverter لا يحتفظ بحالة: استدعِه من DoconutHost.Services أينما احتجت إليه وأعد استخدامه بحرية.

csharp
// Resolve DocumentConverter from DoconutHost.Services; its constructor is internal, so never `new` it.
Stream pdf = await converter.ConvertAsync("contract.docx", ConversionTarget.Pdf, ct: ct);
csharp
// sourceExtension includes the leading dot. password is null unless the document is protected.
Stream png = await converter.ConvertAsync(upload, ".xlsx", ConversionTarget.Png, password: null, ct: ct);
csharp
Stream html = await converter.WordToHtmlAsync("report.docx", ct);
csharp
Stream docx = await converter.HtmlToWordAsync(html, ConversionTarget.Docx, ct);

هناك تفصيلان سهلان الخطأ فيهما: يجب أن يتضمن sourceExtension في نسخة الدفق النقطة الأولية (".xlsx" وليس "xlsx")، وإلا لن يتم التعرف عليه. وعلى الرغم من اسمه، فإن WordToHtmlAsync يُعيد Task<Stream> وليس Task<string> — وثيقة HTML (الصور مدمجة كـ Base64) تصل كدفق، مثل كل نتيجة أخرى.

في وحدة تحكم MVC 5

اجعل الإجراء غير متزامن واستخدم await للتحويل:

csharp
[HttpPost]
public async Task<ActionResult> ToPdf(HttpPostedFileBase file)
{
    var converter = Doconut.DoconutHost.Services.GetRequiredService<DocumentConverter>();
    Stream pdf = await converter.ConvertAsync(
        file.InputStream, Path.GetExtension(file.FileName), ConversionTarget.Pdf,
        password: null, ct: Response.ClientDisconnectedToken);
    return File(pdf, "application/pdf", Path.GetFileNameWithoutExtension(file.FileName) + ".pdf");
}

في Web Forms: لا تحظر أبدًا أثناء التحويل

صفحة Web Forms تُنفَّذ في سياق طلب أحادي الخيط. ConvertAsync تستأنف على ذلك السياق عند الانتهاء، لذا فإن الصفحة التي تنتظر النتيجة بشكل متزامن — .Result، .Wait()، .GetAwaiter().GetResult() — تحتجز الخيط الذي يحتاجه التحويل لإكمال عمله. الطلب لا يعود أبداً. المتصفح يظل يدور، ولا يُسجَّل شيء في IIS، وتستمر باقي أجزاء الموقع في العمل، فيظهر الأمر كتحويل بطيء وليس كـ deadlock.

ضع الخاصية Async="true" في الصفحة وشغِّل التحويل كمهمة غير متزامنة للصفحة:

aspx
<%@ Page Language="C#" Async="true" CodeBehind="Convert.aspx.cs" Inherits="MyApp.Convert" %>
csharp
// Web Forms: the @Page directive needs Async="true", and the conversion runs as a page async task.
// Blocking on it instead (.Result, .Wait(), .GetAwaiter().GetResult()) deadlocks the request:
// it never returns, and nothing is logged.
protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack) return;

    RegisterAsyncTask(new PageAsyncTask(async ct =>
    {
        var converter = Doconut.DoconutHost.Services.GetRequiredService<DocumentConverter>();

        using (var pdf = await converter.ConvertAsync(
                   Server.MapPath("~/App_Data/contract.docx"), ConversionTarget.Pdf, ct: ct))
        using (var ms = new MemoryStream())
        {
            if (pdf.CanSeek) pdf.Position = 0;
            await pdf.CopyToAsync(ms);

            Response.ContentType = "application/pdf";
            Response.AddHeader("Content-Disposition", "attachment; filename=contract.pdf");
            Response.BinaryWrite(ms.ToArray());
            // Context, not HttpContext.Current: after an await the latter can be null.
            Context.ApplicationInstance.CompleteRequest();
        }
    }));
}

بدون Async="true" في توجيه @Page، يتم تجاهل RegisterAsyncTask بصمت. بعد await، استخدم Context الخاص بالصفحة؛ قد يكون HttpContext.Current null هناك.

صيغ الهدف

text
Pdf, Docx, Doc, Html, Xlsx, Pptx, Png, Jpeg, Csv, Tiff, Bmp, Gif, Svg, Xml,
Txt, Xls, Jp2, Rtf, Odt, Ods, Odp, Epub, Xps, Webp

ليس كل مصدر يتحول إلى كل هدف: كل عائلة صيغ المصدر (Word, Excel, PowerPoint, PDF, CAD, Image, Email, Diagram, Project, PSD, مستند ويب) لها مجموعة خاصة من الأهداف المسموح بها. لا تقم بترميز هذه القائمة يدوياً كقائمة أهداف لواجهة المستخدم الخاصة بك: ?convert=open تُعيد allowedTargets للملف المرفوع، وهذا هو ما يجب أن يُستخدم لتحديد الاختيار.

عنصر واجهة المستخدم القابل للإدماج

نقاط النهاية ?convert=open|run|download للعنصر تُخدم بواسطة DocImage.axd وتكون معطلة بشكل افتراضي. قم بتمكينها بجوار تسجيل الإضافة:

csharp
Doconut.DoconutHost.Initialize(options =>
{
    options.LicensePath = HostingEnvironment.MapPath("~/wwwroot/Doconut.Viewer.lic");
    options.AddPlugin<Doconut.Plugins.Converter.ConverterPlugin>();
    options.AddConverterWidget(widget =>
    {
        widget.MaxUploadMb = 25;
    });
});
// System.Web reads the whole upload before Doconut sees it: keep maxRequestLength (KB) and
// maxAllowedContentLength (bytes) in Web.config above the widget's MaxUploadMb.
html
<div id="doconut-convert"></div>
<script src="/doconut-res/js/doconutConverter.js"></script>
<script>
  Doconut.convert('#doconut-convert', { basePath: '/DocImage.axd', maxUploadMb: 25 });
</script>

شيئان يجب التحقق منهما عندما لا يعمل العنصر بشكل صحيح:

  • basePath: '/DocImage.axd'. الافتراضي للعنصر هو /doconut وهو نقطة النهاية لـ ASP.NET Core. في هذه الحزمة، نقاط النهاية هي المعالج DocImage.axd من Web.config.
  • السكريبت ونقاط النهاية مستقلان. وحدة الموارد تُقدم doconutConverter.js سواء كان العنصر مفعلاً أم لا. بدون AddConverterWidget(), يحمّل العنصر، يرسم منطقة السحب الخاصة به، ويظهر بشكل صحيح تماماً — وإجراءه الأول يُعيد 404.

حدود التحميل

يقوم ASP.NET بقراءة كامل جسم الطلب قبل تشغيل DocImage.axd. إذا كان التحميل أعلى من MaxUploadMb ولكن أقل من حدود المضيف، يحصل العنصر على استجابة JSON 413 ("File is too large."). إذا كان التحميل أعلى من حدود المضيف، يتم رفضه من قبل IIS أولاً، مع صفحة خطأ لا يستطيع العنصر قراءتها. احتفظ بحدود المضيف في Web.config فوق حد العنصر:

xml
<system.web>
  <httpRuntime maxRequestLength="30720" />           <!-- KILOBYTES: 30 MB -->
</system.web>
<system.webServer>
  <security>
    <requestFiltering>
      <requestLimits maxAllowedContentLength="31457280" />  <!-- BYTES: 30 MB -->
    </requestFiltering>
  </security>
</system.webServer>

تخصيص العنصر

الخيارات التي تُمرّر إلى Doconut.convert(selector, options):

الخيارالنوعالافتراضيملاحظات
basePathstring/doconutعنوان URL لنقطة النهاية. اضبط '/DocImage.axd' في هذه الحزمة
resPathstring/doconut-resمقبول للتوافق مع عناصر Doconut الأخرى؛ عنصر التحويل لا يُنشئ أي URL منه
maxUploadMbnumber25تحقق مسبق من جانب العميل فقط؛ الخادم يفرض الحد الخاص به
licenseUrlstring | nullnullيحوّل إشعار العلامة المائية على شاشة النتيجة إلى رابط
labelsobject{}يتجاوز أي جزء من سلاسل العنصر الإنجليزية

الاستدعاءات الراجعة:

الاستدعاءيُنفّذ عندماالحمولة
onReady()العنصر قد عرض شاشة السحب الخاصة به—
onSourceLoaded({ token, pages, sourceExt, allowedTargets })?convert=open نجحرمز المصدر، عدد الصفحات، امتداد المصدر (بدون نقطة أمامية)، الأهداف المسموح بها
onConverted({ downloadToken, resultToken, resultPages, downloadName, watermarked, target })?convert=run نجحاستجابة التشغيل بالإضافة إلى target المطلوب
onDownload({ downloadName, downloadToken })المستخدم ينقر على تنزيليُنفّذ جنباً إلى جنب مع تنزيل المتصفح نفسه
onError({ phase, message })طلب فتح أو تشغيل فشلphase إما 'open' أو 'run'؛ message هو خطأ الخادم المُنقّى

Doconut.convert() يُعيد نسخة العنصر: reset() تُعيد إلى شاشة السحب، loadFile(file) يبدأ العملية بملف File، و destroy() يزيله.

بناء الواجهة الأمامية الخاصة بك

الودجت هو عميل لهذا العقد HTTP على DocImage.axd:

المسارالغرضاستجابة النجاح
POST /DocImage.axd?convert=open (multipart, field file)رفع وفتح مستند مصدر200 — { token, pages, sourceExt, allowedTargets }
POST /DocImage.axd?token=<token>&convert=run&target=<ext>تحويل المصدر المرفوع إلى target200 — { downloadToken, resultToken, resultPages, downloadName, watermarked }
GET /DocImage.axd?convert=download&token=<downloadToken>بث الملف المحول200 — الملف, Content-Disposition: attachment

يتم الاحتفاظ بالمصادر المرفوعة لمدة 30 دقيقة؛ بعد ذلك، تُجيب run بـ 404 ويجب فتح الملف مرة أخرى. يحصل downloadToken على نافذة زمنية خاصة به مدتها 30 دقيقة عند اكتمال التحويل. resultToken هو رمز عارض عادي يتبع عمر جلسة العارض.

sourceExt في استجابة open لا يحتوي على نقطة في البداية ("docx") — وهو عكس معامل sourceExtension في ConvertAsync.

المسارالحالةمتىالمحتوى
أي404الودجت غير مفعّل (AddConverterWidget() لم يُستدعَ أبداً)فقط الحالة
أي405الفعل غير صحيح (open/run يتطلبان POST، download يتطلب GET)فقط الحالة
open413الرفع يتجاوز MaxUploadMb (ولكن ليس حدود IIS){ "error": "File is too large." }
open400لا يوجد جسم multipart، لا ملف، أو نوع لا يمكن تحويله{ "error": "..." }
open403نوع الملف يحتاج إلى قدرة لا تمنحها الرخصة{ "error": "..." }
run400رمز غير صالح، target غير معروف، أو هدف غير موجود في allowedTargets{ "error": "..." }
run404انتهت صلاحية الرفع أو لم يُفتح أبداً{ "error": "Upload expired — please re-open the file." }
open, run500فشل المعالجة{ "error": "<sanitized message>" }
download400 / 404رمز تحميل غير صالح، غير معروف، أو منتهي الصلاحيةفقط الحالة

ملكية الموارد

المستدعي يمتلك الـ MemoryStream الذي تُعيده عملية التحويل ويجب تحريره بعد النسخ أو الإرجاع (دالة File(stream, …) في MVC تقوم بتحريره لك). لا تقم بإنشاء أو تحرير DocumentConverter بنفسك — مُنشئه داخلي.

إضافة العلامة المائية

حالة الترخيصبدء التشغيلنتيجة التحويل
رخصة عارض مدفوعة تمنح Converterيبدأنظيف — watermarked: false
رخصة مؤقتة/تجريبية نشطةيبدأتحويل مع علامة مائية تجريبية — watermarked: true
لا رخصة، ملف TRIAL قديم، أو رخصة بدون ConverterApplication_Start يرمي استثناء؛ كل طلب يُجيب بـ 500 فارغ—
رخصة مؤقتة/تجريبية منتهيةيبدأتحويل مع علامة مائية تجريبية — watermarked: true

يمكن بناء واختبار التكامل من البداية إلى النهاية باستخدام رخصة تجريبية قبل الشراء — فقط بايتات الناتج تتغير.

استكشاف الأخطاء وإصلاحها

العَرَضالتحقق
كل طلب يُجيب بـ 500 فارغ بعد إضافة الإضافةالرخصة تمنح Converter — سجل أحداث Windows، مصدر ASP.NET
إيجاد DocumentConverter يرمي استثناءAddPlugin<ConverterPlugin>() موجود في DoconutHost.Initialize
تحويل Web Forms لا يعود أبداًالصفحة تتوقف على ConvertAsync — استخدم Async="true" و RegisterAsyncTask
تحويل الدفق يقول إن الصيغة غير مدعومةsourceExtension يتضمن النقطة في البداية
الودجت يُحمَّل لكن طلباته تُعيد 404AddConverterWidget() لم يُستدعَ، أو basePath ليس '/DocImage.axd'
رفع كبير يُظهر صفحة خطأ IIS بدلاً من رسالة الودجتmaxRequestLength / maxAllowedContentLength أقل من MaxUploadMb
هدف مفقوداستخدم allowedTargets من convert=open
انتهت صلاحية التحميلأعد convert=open / convert=run؛ الرموز مؤقتة عن قصد

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