תוסף ממיר

המרת מסמכים ל-24 פורמטים יעד

תוסף הממיר הופך את Doconut לשירות המרת מסמכים. הוא תורם את המנוע מאחורי הממשק הציבורי DocumentConverter, ו‑— במידה שתבחר — וידג'ט נשלף עם חוזה HTTP משלו, כך שתוכל להמיר מסמכים מ‑C#, מהוידג'ט, או מממשק קדמי שאתה בונה בעצמך.

התקנת החבילה

התקן את תוסף הממיר היציב האחרון:

bash
dotnet add package Doconut.NET6.Converter

כדי לעגן את התוסף לגרסה 26.7.0 הנוכחית, העבר את הגרסה בנפרד:

bash
dotnet add package Doconut.NET6.Converter --version 26.7.0

שמור על חבילת הממיר באותה גרסה כמו Doconut.NET6. מזהה החבילה הוא Doconut.NET6.Converter; .26.7.0 מופיע רק בשם הקובץ .nupkg שהורד.

רישום התוסף

אין שיטה AddConverter() — מודל הפלאגינים של Doconut הוא אחיד. כל תוסף, כולל הממיר, נרשם באותו אופן: קרא AddPlugin<TPlugin>() בתוך AddDoconut(). ConverterPlugin מגיע בחבילת NuGet משלו, Doconut.NET6.Converter, מותקן לצד חבילת הצופה הבסיסית.

csharp
builder.Services.AddDoconut(options =>
{
    options.LicensePath = "Doconut.Viewer.lic";
    options.AddPlugin<Doconut.Plugins.Converter.ConverterPlugin>();
});

קריאה זו זורקת שגיאה בעת ההפעלה עבור רישיון חסר, קובץ TRIAL מדור קודם, או רישיון שאינו זמני שאינו מעניק את היכולת Converter — InvalidOperationException שנוצר מתוך AddDoconut(), לפני שהאפליקציה מגישה בקשות. רישומי Demo/NFR זמניים מתקבלים; לאחר תום תוקפם בלוח השנה, ההמרה נשארת זמינה עם פלט מסומן במים. אין רמת חינם שקטה. ראה הגדרת רישיון לקבלת מידע כיצד נטענים רישיונות.

המרה מ‑C#

כל המרה מחזירה MemoryStream ניתן לחיפוש הממוקם ב‑0, מוכן לקריאה או העתקה מיידית. קבל את DocumentConverter מה‑DI בכל מקום שבו אתה צריך אותו — הוא חסר מצב לפי תכנון, ולכן ניתן להשתמש במופע יחיד בבטחה בבקשות מרובות.

csharp
// הזרק DocumentConverter; הבנאי שלו פנימי, ולכן לעולם אל תשתמש ב-`new`.
Stream pdf = await converter.ConvertAsync("contract.docx", ConversionTarget.Pdf, ct: ct);
csharp
// sourceExtension כולל את הנקודה המקדימה. password הוא null אלא אם המסמך מוגן.
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 ב‑overload של ה‑stream חייב לכלול את הנקודה המקדימה (".xlsx", ולא "xlsx") — הממיר משווה זאת מול קטלוג הפורמטים והרחבה ללא נקודה לא תיפתר. ולמרות שמו, WordToHtmlAsync מחזיר Task<Stream>, ולא Task<string> — אתה מקבל את מסמך ה‑HTML (תמונות משובצות כ‑Base64) כ‑stream, בדיוק כמו כל תוצאה אחרת של המרה.

פורמטים יעד

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/Task, PSD, מסמך אינטרנט) למערך הקבוע שלו של יעדים מותרים. אל תקודד קבוע את המונה הזה כרשימת היעדים בממשק המשתמש שלך: ?convert=open מחזיר את ה‑allowedTargets האמיתי עבור כל קובץ שהועלה זה עתה, וזה מה שצריך להניע את בוחר היעדים.

וידג'ט נשלף

קצות ה?convert=open|run|download של הוידג'ט הם אופציונליים ומושבתים כברירת מחדל — מאובטחים כברירת מחדל. אפשר אותם בצד השרת, יחד עם רישום הפלאגין:

csharp
builder.Services.AddDoconut(options =>
{
    options.LicensePath = "Doconut.Viewer.lic";
    options.AddPlugin<Doconut.Plugins.Converter.ConverterPlugin>();
    options.AddConverterWidget(widget =>
    {
        widget.MaxUploadMb = 25;
    });
});
html
<div id="doconut-convert"></div>
<script src="/doconut-res/js/doconutConverter.js"></script>
<script>
  Doconut.convert('#doconut-convert', { basePath: '/doconut', resPath: '/doconut-res', maxUploadMb: 25 });
</script>

בלי AddConverterWidget(), שלושת קצות ה?convert= משיבים 404 — אך קובץ ה‑JS עצמו עדיין מוגש בכל מקרה (זהו משאב סטטי משובץ פשוט; רק הקצות אליהם הוא מתקשר מגודרים). AddConverterWidget() עדיין דורש שהפלאגין Converter יהיה רשום ורישיון שמעניק Converter — הוא אינו מעניק זכויות המרה בעצמו.

התאמת הוידג'ט

אפשרויות אתחול שנשלחות לDoconut.convert(selector, options):

אפשרותסוגברירת מחדלהערות
basePathstring/doconutנתיב הבסיס עבור קצות ה?convert=; הוא חייב להתאים לסניף ה‑ASP.NET שבו UseDoconut() מותקן בפועל (בדרך כלל מתואם דרך MiddlewarePath)
resPathstring/doconut-resמתקבל לצורך עקביות תצורה עם וידג'טים אחרים של Doconut; וידג'ט הממיר כרגע אינו בונה שום URL ממנו
maxUploadMbnumber25בדיקה מוקדמת רק בצד הלקוח — דוחה קובץ גדול מדי לפני ההעלאה. השרת אוכף את המגבלה שלו באופן עצמאי ומשיב 413 אם היא חורגת
licenseUrlstring | nullnullכאשר מוגדר, ממיר את הודעת סימן המים על מסך התוצאה לקישור ל‑URL זה
labelsobject{}עוקף כל תת‑קבוצה של המחרוזות ברירת המחדל באנגלית של הוידג'ט (טקסט גרירה, כפתורים, הודעות aria‑live, הודעות שגיאה)

קריאות חזרה:

קריאה חזרהמתרחשת כאשרנתונים
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() מחזיר את מופע הוידג'ט עצמו — שמור עליו כדי לשלוט בוידג'ט באופן תכנותי:

javascript
const conv = Doconut.convert('#doconut-convert', { basePath: '/doconut' });
conv.reset();         // חזרה למסך idle/drop; לא מפעיל מחדש את onReady
conv.loadFile(file);  // מתחיל את הזרימה עם אובייקט File; no-op אלא אם הוא כרגע במצב idle
conv.destroy();       // מסיר מאזינים, מרוקן את ה‑mount; המופע אינו ניתן לשימוש לאחר זאת

בנה ממשק משתמש משלך

הוידג'ט הוא רק לקוח לחוזה HTTP זה — בנה ממשק משתמש משלך שמתחבר אליו ישירות לחוויית משתמש שונה. שלושת המסלולים נמצאים תחת סניף ה‑ASP.NET שבו UseDoconut() מותקן (בדרך כלל /doconut):

נתיבמטרהתגובה מוצלחת
POST ?convert=open (multipart, field file)העלאה ופתיחה של מסמך מקור לתצוגה מקדימה200 — { token, pages, sourceExt, allowedTargets }
POST ?token=<token>&convert=run&target=<ext>המרת המקור השמור לtarget200 — { downloadToken, resultToken, resultPages, downloadName, watermarked }
GET ?convert=download&token=<downloadToken>הזרמת הקובץ המומר200 — בתים של קובץ, Content-Disposition: attachment, Cache-Control: no-store

בתים של המקור שהועלו נשמרים בצד השרת עם TTL של 30 דקות; ברגע שהחלון הזה פג, run משיב 404 והקובץ חייב להיפתח מחדש. התוצאה המומרת חיה באותו מאגר — downloadToken מקבל חלון של 30 דקות רענן כאשר ההמרה מסתיימת — בעוד resultToken הוא אסימון מושב צופה רגיל שהחיים שלו תלויות במטמון מושב הצופה, באופן עצמאי מהמאגר.

sourceExt בתגובה של open אינו כולל נקודה מקדימה (למשל "docx") — ההפך מהקונבנצייה של הפרמטר sourceExtension בDocumentConverter.ConvertAsync, הדורש נקודה.

מצבי כשל, מקובצים לפי נתיב:

נתיבסטטוסמתיגוף
any404הוידג'ט אינו מופעל (AddConverterWidget() לא נקרא אף פעם) — נבדק לפני שכל אחד משלושת המסלולים נשלחרק סטטוס
any405verb HTTP שגוי (open/run דורשים POST; download דורש GET)רק סטטוס
open413הקובץ שהועלה חורג מMaxUploadMb{ "error": "File is too large." }
open400אין גוף multipart, אין קובץ, או סיומת מקור שלא ניתנת להמרה{ "error": "..." }
run400אסימון פגום (לא GUID), או target שלא ניתן לנתח לConversionTarget{ "error": "Invalid token." } / { "error": "Unknown target format." }
run400target אינו בallowedTargets של המקור{ "error": "That target format is not available for this file." }
run404ההעלאה השמורה פגה (TTL של 30 דקות) או שהאסימון מעולם לא נפתח{ "error": "Upload expired — please re-open the file." }
open, run500העיבוד נכשל פנימית{ "error": "<sanitized message>" } — מסונן באותו אופן כמו כל נתיב שגיאה של Doconut; לעולם לא דולף שמות מנוע פנימיים
download400אסימון פגום (לא GUID)רק סטטוס
download404אסימון הורדה לא ידוע או פגוםרק סטטוס

בעלות על המשאב

הממיר מחזיר MemoryStream שניתן לחיפוש וממוקם באפס. הקורא הוא בעל הזרם הזה ויש לפנות אותו לאחר ההעתקה או החזרת התוכן שלו. שירות DocumentConverter עצמו הוא חסר מצב ונפתר מהזרקת תלות; אל תבנה או תפסול את השירות באופן ידני.

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

פתרון בעיות

סימפטוםבדיקה
פתירת DocumentConverter נכשלההרשמה של ConverterPlugin התרחשה בתוך AddDoconut()
היישום נכשל בזמן ההפעלההרישיון שהוטען מעניק Converter
המרת הזרם אומרת שהפורמט אינו נתמךsourceExtension כולל את הנקודה המקדימה
קוד ה‑JavaScript של הווידג'ט נטען אך הבקשות מחזירות 404AddConverterWidget() לא נקרא
בקשות הווידג'ט משתמשות ב‑URL שגויbasePath תואם את הסניף שבו UseDoconut() ממופה
היעד חסרהשתמש בallowedTargets שמוחזר על ידי convert=open; לא כל מקור תומך בכל יעד של enum
ההורדה פגהחזור על convert=open/convert=run; אסימוני המאגר הם זמניים בכוונה

סימון מים

עם ConverterPlugin רשום, הרישיון של המארח נמצא באחד משלושה מצבים:

מצב הרישיוןשער הפתיחהפלט ההמרה
רישיון צופה בתשלום המעניק Converter, בתוך תקופת התוקף שלועוברנקי — watermarked: false
רישיון הערכה פעיל (דמו/NFR)עוברמומר בהצלחה, מסומן במים של ההערכה — watermarked: true
ללא רישיון, קובץ TRIAL מיושן, או רישיון שאינו זמני שאינו מעניק Converterהיישום לעולם לא מתחיל — שער הפתיחה המתואר למעלה זורק—
רישיון זמני/דמו שפגההרשמה נשארת לאחר הפקיעהמומר עם סימן המים של ההערכה — watermarked: true

שתי דרכי הקריאה מחשבות את הדגל מאותו כלל: הפסקה של DocumentConverter ב‑C# נגזרת פנימית ממצב ה‑IsViewerLicensed וה‑IsTemporary של הרישיון, והמתאם של ?convert=run בווידג'ט מבצע את הבדיקה המקבילה (IsViewerLicensed && !IsTrial && !IsTemporary) כדי למלא את השדה watermarked שהוא מחזיר. ניתן לבנות אינטגרציה ולבדוק אותה מקצה לקצה ברישיון הערכה לפני הרכישה — רק בתים הפלט משתנים.

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