Plugin Chuyển Đổi

Chuyển đổi tài liệu sang 45 định dạng mục tiêu

Plugin Converter biến Doconut thành một dịch vụ chuyển đổi tài liệu. Nó cung cấp động cơ phía sau lớp mặt nạ công cộng DocumentConverter, và — khi chọn — một widget có thể chèn sẵn với hợp đồng HTTP riêng, cho phép bạn chuyển đổi tài liệu từ C#, từ widget, hoặc từ giao diện phía trước mà bạn tự viết.

Cài đặt gói

Cài đặt plugin Converter mới nhất và ổn định:

bash
dotnet add package Doconut.NETStandard.Converter

Để cố định plugin vào phiên bản 26.8.0 hiện tại, truyền phiên bản riêng:

bash
dotnet add package Doconut.NETStandard.Converter --version 26.8.0

Giữ gói Converter ở cùng phiên bản với Doconut.NETStandard. ID gói là Doconut.NETStandard.Converter; .26.8.0 chỉ xuất hiện trong tên tệp .nupkg đã tải về.

Đăng ký plugin

Không có phương thức AddConverter() — mô hình plugin của Doconut là đồng nhất. Mỗi plugin, bao gồm Converter, được đăng ký theo cùng một cách: gọi AddPlugin<TPlugin>() bên trong AddDoconut(). ConverterPlugin được cung cấp trong gói NuGet riêng, Doconut.NETStandard.Converter, được cài đặt cùng với gói viewer cơ bản.

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

Lệnh này sẽ ném lỗi khi khởi động nếu thiếu giấy phép, tệp TRIAL cũ, hoặc giấy phép không tạm thời không cấp quyền Converter — một InvalidOperationException được phát sinh từ bên trong AddDoconut(), trước khi ứng dụng phục vụ yêu cầu. Các đăng ký Demo/NFR tạm thời được chấp nhận; sau khi hết hạn theo lịch, việc chuyển đổi vẫn khả dụng nhưng đầu ra có dấu watermark. Không có cấp miễn phí im lặng. Xem License Setup để biết cách tải giấy phép.

Chuyển đổi từ C#

Mỗi lần chuyển đổi trả về một MemoryStream có thể tìm kiếm, vị trí ở 0, sẵn sàng để đọc hoặc sao chép ngay lập tức. Lấy DocumentConverter từ DI bất cứ nơi nào bạn cần — nó không có trạng thái theo thiết kế, vì vậy một thể hiện duy nhất có thể tái sử dụng an toàn trong các yêu cầu.

viewer.Converter.GetConverter() không tồn tại ở đây. Việc chuyển đổi không còn được truy cập qua thể hiện viewer: thay vào đó hãy tiêm Doconut.DocumentConverter.

csharp
// Inject DocumentConverter; 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);

Hai chi tiết dễ bị nhầm lẫn: sourceExtension trong overload cho stream phải bao gồm dấu chấm đầu (".xlsx", không phải "xlsx") — bộ chuyển đổi sẽ so sánh nó với danh mục định dạng và một phần mở rộng không có dấu chấm sẽ không được giải quyết. Và mặc dù tên gọi, WordToHtmlAsync trả về Task<Stream>, không phải Task<string> — bạn nhận được tài liệu HTML (hình ảnh được nhúng dưới dạng Base64) dưới dạng stream, giống như mọi kết quả chuyển đổi khác.

Định dạng mục tiêu

ConversionTarget (namespace Doconut.Configs.Conversion) có 45 thành viên:

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, Msg, Eml, Emlx, Mhtml,
Xlsm, Xlsb, Ppt, Docm, Dot, Dotx, Dotm, Vsdx, Vssx, Vstx, Vsdm, Vssm, Vstm,
Vdx, Vsx, Vtx, Ico

Enum này bao phủ mọi họ nguồn. Thư viện trước đây có kiểu *ConfigConverter riêng cho mỗi họ — WordConfigConverter, ExcelConfigConverter, v.v. — mỗi loại có enum lồng EnTargetFormat riêng, cộng với enum SourceFormatConverter cho đầu vào. Tất cả đã được loại bỏ; xem migration guide.

Không phải mọi nguồn đều chuyển đổi sang mọi mục tiêu — plugin ánh xạ mỗi họ định dạng nguồn (Word, Excel, PowerPoint, PDF, CAD, Image, Email, Diagram, Project/Task, PSD, tài liệu web) tới một tập hợp mục tiêu cho phép cố định. Đừng mã cứng enum này làm danh sách mục tiêu cho UI của bạn: ?convert=open trả về allowedTargets thực tế cho tệp vừa được tải lên, và đó là dữ liệu nên điều khiển bộ chọn.

Tiện ích nhúng sẵn

Các endpoint ?convert=open|run|download của tiện ích là tùy chọn và mặc định bị tắt — an toàn theo mặc định. Kích hoạt chúng phía máy chủ, cùng với việc đăng ký plugin:

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>

Nếu không gọi AddConverterWidget(), ba endpoint ?convert= sẽ trả về 404 — nhưng tệp JS vẫn được phục vụ (đó là một tài nguyên tĩnh nhúng; chỉ các endpoint mà nó giao tiếp mới bị giới hạn). AddConverterWidget() vẫn yêu cầu plugin Converter được đăng ký và một giấy phép cho phép Converter — nó không tự động cấp quyền chuyển đổi.

Tùy chỉnh tiện ích

Các tùy chọn khởi tạo được truyền vào Doconut.convert(selector, options):

Tùy chọnKiểuMặc địnhGhi chú
basePathstring/doconutĐường dẫn cơ sở cho các endpoint ?convert=; phải khớp với nhánh ASP.NET nơi UseDoconut() thực sự được gắn (thường được điều phối qua MiddlewarePath)
resPathstring/doconut-resĐược chấp nhận để đồng nhất cấu hình với các tiện ích Doconut khác; tiện ích chuyển đổi hiện không xây dựng URL nào từ giá trị này
maxUploadMbnumber25Kiểm tra trước phía client — từ chối tệp quá lớn trước khi tải lên. Máy chủ áp dụng giới hạn riêng và trả về 413 nếu vượt quá
licenseUrlstring | nullnullKhi được đặt, chuyển thông báo watermark trên màn hình kết quả thành một liên kết tới URL này
labelsobject{}Ghi đè bất kỳ tập con nào của các chuỗi mặc định tiếng Anh của tiện ích (văn bản thả, nút, thông báo aria-live, thông báo lỗi)

Các callback:

CallbackKhi nào được gọiDữ liệu
onReady()Tiện ích đã hiển thị màn hình chờ/thả—
onSourceLoaded({ token, pages, sourceExt, allowedTargets })Khi ?convert=open thành côngtoken phiên nguồn, số trang, phần mở rộng nguồn (không có dấu chấm), danh sách các định dạng đích được phép
onConverted({ downloadToken, resultToken, resultPages, downloadName, watermarked, target })Khi ?convert=run thành côngcác trường giống như phản hồi run, cộng thêm target đã yêu cầu
onDownload({ downloadName, downloadToken })Người dùng nhấp vào liên kết Tải xuốngđược kích hoạt cùng với tải xuống gốc của trình duyệt — không can thiệp hay thay thế
onError({ phase, message })Yêu cầu mở hoặc chạy gặp lỗiphase là 'open' hoặc 'run'; message là thông báo lỗi đã được làm sạch (hoặc thông báo phía client cho kiểm tra kích thước tải lên)

Doconut.convert() trả về chính thể hiện của tiện ích — giữ lại để điều khiển tiện ích bằng mã:

javascript
const conv = Doconut.convert('#doconut-convert', { basePath: '/doconut' });
conv.reset();         // quay lại màn hình chờ/thả; không gọi lại onReady
conv.loadFile(file);  // bắt đầu luồng với một đối tượng File; không làm gì nếu không ở trạng thái chờ
conv.destroy();       // xóa các listener, dọn dẹp phần gắn; thể hiện không còn sử dụng được sau đây

Xây dựng giao diện người dùng của riêng bạn

Tiện ích chỉ là một client cho hợp đồng HTTP này — bạn có thể xây dựng giao diện riêng trực tiếp dựa trên nó để tạo trải nghiệm người dùng khác. Ba route đều nằm dưới nhánh ASP.NET nơi UseDoconut() được gắn (thường là /doconut):

RouteMục đíchPhản hồi thành công
POST ?convert=open (multipart, trường file)Tải lên và mở tài liệu nguồn để xem trước200 — { token, pages, sourceExt, allowedTargets }
POST ?token=<token>&convert=run&target=<ext>Chuyển đổi nguồn đã lưu sang target200 — { downloadToken, resultToken, resultPages, downloadName, watermarked }
GET ?convert=download&token=<downloadToken>Phát luồng tệp đã chuyển đổi200 — byte tệp, Content-Disposition: attachment, Cache-Control: no-store

Các byte nguồn được lưu tạm phía máy chủ với TTL 30 phút; khi thời gian này hết, run sẽ trả về 404 và tệp phải được mở lại. Kết quả đã chuyển đổi cũng nằm trong cùng kho lưu — downloadToken nhận một cửa sổ 30 phút mới khi chuyển đổi hoàn tất — trong khi resultToken là token phiên xem thông thường, thời gian sống phụ thuộc vào bộ nhớ cache của viewer, độc lập với kho lưu.

sourceExt trong phản hồi open không có dấu chấm đầu (ví dụ "docx") — ngược lại với tham số sourceExtension của DocumentConverter.ConvertAsync, yêu cầu có dấu chấm.

Các chế độ lỗi, nhóm theo tuyến:

RouteTrạng tháiKhi nàoNội dung
bất kỳ404Tiện ích chưa được bật (AddConverterWidget() chưa bao giờ được gọi) — kiểm tra trước khi bất kỳ route nào được xử lýchỉ trạng thái
bất kỳ405Động từ HTTP sai (open/run yêu cầu POST; download yêu cầu GET)chỉ trạng thái
open413Tệp tải lên vượt quá MaxUploadMb{ "error": "File is too large." }
open400Không có body multipart, không có tệp, hoặc phần mở rộng nguồn không thể chuyển đổi{ "error": "..." }
run400Token không hợp lệ (không phải GUID), hoặc target không phân tích được thành ConversionTarget{ "error": "Invalid token." } / { "error": "Unknown target format." }
run400target không nằm trong allowedTargets của nguồn{ "error": "That target format is not available for this file." }
run404Tệp đã lưu đã hết hạn (TTL 30 phút) hoặc token chưa bao giờ được mở{ "error": "Upload expired — please re-open the file." }
open, run500Xử lý nội bộ thất bại{ "error": "<sanitized message>" } — được làm sạch theo cùng cách như mọi đường lỗi Doconut khác; không bao giờ rò rỉ tên engine nội bộ
download400Token không hợp lệ (không phải GUID)chỉ trạng thái
download404Token tải xuống không tồn tại hoặc đã hết hạnchỉ trạng thái

Quyền sở hữu tài nguyên

Bộ chuyển đổi trả về một MemoryStream có thể tìm kiếm, vị trí ở 0. Người gọi sở hữu luồng này và nên giải phóng nó sau khi sao chép hoặc trả lại nội dung. Dịch vụ DocumentConverter tự nó không có trạng thái và được giải quyết từ dependency injection; không tự tạo hoặc giải phóng dịch vụ này một cách thủ công.

Đối với widget web, các kho lưu tải lên và tải xuống có TTL độc lập 30 phút. Một resultToken của viewer tuân theo thời gian sống của phiên viewer thay vào đó. Đóng kết quả viewer không xóa kho tải xuống vẫn còn hợp lệ, và việc đặt lại widget trình duyệt không kéo dài bất kỳ TTL nào.

Khắc phục sự cố

Triệu chứngKiểm tra
Giải quyết DocumentConverter thất bạiConverterPlugin đăng ký đã xảy ra bên trong AddDoconut()
Ứng dụng thất bại khi khởi độngGiấy phép đã tải cho phép Converter
Chuyển đổi luồng báo rằng định dạng không được hỗ trợsourceExtension bao gồm dấu chấm đầu tiên
JavaScript của widget tải nhưng các yêu cầu trả về 404AddConverterWidget() chưa được gọi
Các yêu cầu widget sử dụng URL saibasePath khớp với nhánh nơi UseDoconut() được ánh xạ
Mục tiêu bị thiếuSử dụng allowedTargets trả về bởi convert=open; không phải mọi nguồn đều hỗ trợ mọi mục tiêu enum
Tải xuống đã hết hạnLặp lại convert=open/convert=run; các token lưu tạm thời được tạo có tính tạm thời cố ý

Đánh dấu watermark

Khi ConverterPlugin đã đăng ký, giấy phép của máy chủ nằm trong một trong ba trạng thái:

Trạng thái giấy phépCổng khởi độngKết quả chuyển đổi
Giấy phép viewer trả phí cho phép Converter, trong thời gian hiệu lựcĐạtSạch — watermarked: false
Giấy phép đánh giá hoạt động (demo/NFR)ĐạtChuyển đổi thành công, được dán watermark đánh giá — watermarked: true
Không có giấy phép, một tệp TRIAL cũ, hoặc giấy phép không tạm thời không cho phép ConverterỨng dụng không bao giờ khởi động — cổng khởi động mô tả ở trên ném lỗi—
Giấy phép tạm thời/demo đã hết hạnĐăng ký tồn tại sau khi hết hạnChuyển đổi với watermark đánh giá — watermarked: true

Cả hai đường gọi đều tính cờ dựa trên cùng một quy tắc: lớp mặt nạ C# DocumentConverter suy ra nội bộ từ trạng thái IsViewerLicensed và IsTemporary của giấy phép, và trình xử lý ?convert=run của widget thực hiện kiểm tra tương đương (IsViewerLicensed && !IsTrial && !IsTemporary) để điền trường watermarked mà nó trả về. Một tích hợp có thể được xây dựng và thử nghiệm đầu cuối trên giấy phép đánh giá trước khi mua — chỉ có các byte đầu ra thay đổi.

Trang này có hữu ích không?