Bắt đầu nhanh
Hiển thị tài liệu đầu tiên của bạn trong vài phút
Hướng dẫn này đưa một ứng dụng ASP.NET Core từ một Program.cs trống đến một tài liệu được hiển thị trong trình duyệt: đăng ký máy chủ, gói Viewer đầy đủ (thanh công cụ Viewer, phần gắn Viewer và các ribbon Tìm kiếm/Chú thích tùy chọn), tham chiếu tài nguyên, khởi tạo client, mở tài liệu và thực thi.
Cài đặt máy chủ
AddDoconut() đăng ký các dịch vụ; UseDoconutResources() và UseDoconut() kết nối middleware. Lệnh gọi tài nguyên phải được đặt trước. Các lệnh gọi session cũng cần thiết — bảo mật tài liệu mặc định của Doconut xác thực mỗi yêu cầu trang dựa trên trạng thái session của ASP.NET. Đã đăng ký Doconut trong quá trình Cài đặt chưa? Bỏ qua tới phần tiếp theo.
builder.Services.AddDoconut(options =>
{
options.LicensePath = "Doconut.Viewer.lic";
});
builder.Services.AddSession(); // Doconut document security rides on ASP.NET session state
app.UseSession(); // call UseSession() before UseDoconut()
app.UseDoconutResources(); // must be registered before UseDoconut()
app.UseDoconut();Đối với bố cục đường dẫn kiểu sản xuất, ánh xạ middleware tài liệu tới một nhánh cụ thể và giữ bốn cài đặt đường dẫn đồng bộ:
builder.Services.AddDoconut(options =>
{
options.LicensePath = Path.Combine(AppContext.BaseDirectory, "Doconut.Viewer.lic");
options.MiddlewarePath = "/doconut";
options.ResourcesPath = "/doconut-res";
options.UnsafeMode = false;
});
builder.Services.AddSession();
app.UseRouting();
app.UseSession();
app.UseDoconutResources();
app.Map("/doconut", branch => branch.UseDoconut());MiddlewarePath là một giá trị điều phối; nó không tự động ánh xạ một nhánh ASP.NET Core. Trong ví dụ này máy chủ ánh xạ /doconut, vì vậy client phải sử dụng BasePath: '/doconut'. ResourcesPath cung cấp gói nhúng tại /doconut-res, và đường dẫn tài nguyên hình ảnh của widget do đó là ResPath: '/doconut-res/images'.
Thêm trình xem vào trang
Viewer là lõi bắt buộc của trang. Bề mặt hiển thị của nó sử dụng hai div lồng nhau:
<div id="divDocViewer">
<div id="div_ctlDoc"></div>
</div>Cân nhắc thanh công cụ, các điểm gắn mô-đun và bề mặt Viewer như một thành phần trang duy nhất. Tìm kiếm và Chú thích chèn các ribbon nhúng của chúng vào các điểm gắn tùy chọn, nhưng các mô-đun này không bao giờ độc lập: chúng luôn gắn vào Viewer trên cùng một trang. Sử dụng cùng thứ tự như Doconut.TestApp và Doconut.TestApp.Distributed:
<nav id="toolbar" aria-label="Document viewer controls">
<!-- Viewer navigation, zoom, Search, and Annotation buttons -->
</nav>
<div id="searchBarMount"></div>
<div id="annBarMount"></div>
<div id="divDocViewer">
<div id="div_ctlDoc"></div>
</div>Tham chiếu tài nguyên viewer
Trong một Razor view, dịch vụ Viewer được tiêm sẽ phát ra các thẻ <link> và <script> của viewer theo thứ tự phụ thuộc — widget là một plugin jQuery, vì vậy jQuery phải được tải trước các script của viewer:
@inject Doconut.Viewer Viewer
@Html.Raw(Viewer.ReferenceCss(new CssConfig
{
IncludeBootstrapCss = true,
IncludeViewerCss = true
}))
@Html.Raw(Viewer.ReferenceScripts(new ScriptConfig
{
IncludeJQuery = true,
IncludeBootstrap = true,
IncludeViewerScripts = true
}))Để có gói Viewer đầy đủ, yêu cầu tài nguyên Viewer và các mô-đun cùng nhau:
@Html.Raw(Viewer.ReferenceCss(new CssConfig
{
IncludeBootstrapCss = true,
IncludeViewerCss = true,
IncludeSearchCss = true,
IncludeAnnotationCss = true
}))
@Html.Raw(Viewer.ReferenceScripts(new ScriptConfig
{
IncludeJQuery = true,
IncludeBootstrap = true,
IncludeViewerScripts = true,
IncludeSearchScripts = true,
IncludeSearchBar = true,
IncludeAnnotationScripts = true,
IncludeAnnotationBar = true
}))IncludeViewerCss và IncludeViewerScripts là các cờ cốt lõi bắt buộc. Không bao giờ công bố ví dụ Ribbon Tìm kiếm hoặc Chú thích mà không có chúng, phần gắn Viewer và một thể hiện docViewer. ReferenceCss và ReferenceScripts sẽ bỏ qua tài nguyên của mô-đun tùy chọn khi giấy phép hiện tại không cho phép; Viewer cốt lõi vẫn sẽ khởi động.
Khởi tạo viewer
Widget phía client là một plugin jQuery. Đây là một tập hợp tối thiểu các tùy chọn khởi tạo thực (không phải pseudocode):
let searchBar = null;
let annBar = null;
const objViewer = $('#div_ctlDoc').docViewer({
showThumbs: true,
autoLoad: false,
pageZoom: 100,
FitType: 'width',
BasePath: '/doconut',
ResPath: '/doconut-res/images',
onViewerReady: function () {
// pages are visible; safe to hide a loading spinner here
},
// Forward annotation lifecycle events to the embedded ribbon when it is present.
onAnnLoaded: () => annBar?.handleAnnLoaded(),
onAnnSaved: () => annBar?.handleAnnSaved(),
onAnnSaveError: () => annBar?.handleAnnSaveError(),
onAnnClosed: () => annBar?.handleAnnClosed(),
onError: function (message) {
console.error('Doconut viewer error:', message);
}
});Cách viết hoa thường của các tùy chọn thực sự hỗn hợp — showThumbs, autoLoad, và pageZoom là camelCase, nhưng FitType, BasePath, và ResPath là PascalCase. Không có quy tắc nhất quán; nếu viết sai kiểu chữ, tùy chọn sẽ bị bỏ qua một cách im lặng (widget sẽ quay lại giá trị mặc định thay vì ném lỗi).
Tập hợp gói Viewer đầy đủ
Cả hai ứng dụng tham chiếu .NET 8 đều cài đặt các phần sau cùng nhau trên một trang:
| Phần của gói | Yêu cầu | Cách kết nối |
|---|---|---|
Tài nguyên Viewer, phần gắn và objViewer | Bắt buộc | Bộ render tài liệu cốt lõi |
| Thanh công cụ Viewer | Bắt buộc trong thành phần tham chiếu | Đánh dấu host; các nút gọi cùng objViewer |
| Ribbon Tìm kiếm | Tùy chọn, mô-đun có giấy phép | doconutSearchBar(...).attach(objViewer) |
| Ribbon Chú thích | Tùy chọn, mô-đun có giấy phép | doconutAnnotationBar(...).attach(objViewer) |
Mặc dù thanh công cụ Viewer chính là đánh dấu host, nó được cài đặt cùng với Viewer và không bao giờ được tài liệu hoá như một điều khiển riêng lẻ. Điều này giữ cho bố cục, nhãn, biểu tượng và quy tắc ủy quyền của nó dưới quyền kiểm soát của ứng dụng của bạn trong khi mỗi nút đều điều khiển cùng một thể hiện Viewer:
<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.GotoPage(objViewer.TotalPages())">Last</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>
<button type="button" onclick="objViewer.FitType('height')">Fit height</button>
<button type="button" id="openSearch">Search</button>
<button type="button" id="openAnnotations">Annotations</button>
</nav>Thanh công cụ tham chiếu đầy đủ cũng sao chép wwwroot/js/viewerToolbar.js vào ứng dụng host để hỗ trợ xoay, thumbnail, in, toàn màn hình, bố cục và các trợ giúp trạng thái nút. Tải tệp host này sau Viewer.ReferenceScripts(...). Giữ trợ giúp và đánh dấu <nav id="toolbar"> của nó cùng nhau khi sao chép triển khai demo đầy đủ.
Giữ thứ tự khởi tạo gói được sử dụng bởi cả hai ứng dụng tham chiếu:
- Phát ra tài nguyên Viewer, Search và Annotation cùng nhau.
- Hiển thị thanh công cụ Viewer, các điểm gắn Ribbon và phần gắn Viewer cùng nhau.
- Khởi tạo
docViewerđầu tiên. - Tạo mỗi Ribbon có giấy phép và gắn nó vào cùng một
objViewer. - Mở tài liệu và giữ token của nó cho các yêu cầu mô-đun.
Doconut.TestApp.Distributed giữ nguyên bố cục UI này và cùng trợ giúp thanh công cụ Viewer. Giá trị yêu cầu access bổ sung và cài đặt thử lại render bất đồng bộ thuộc về truyền tải phân tán; chúng không thay đổi cách Viewer, thanh công cụ hoặc Ribbon được lắp ráp.
Các biện pháp bảo vệ phía server rất quan trọng: khi một khả năng tùy chọn không khả dụng, script của nó sẽ không được phát ra, do đó hàm plugin jQuery của nó không tồn tại.
<script>
let currentToken = '';
const refitViewer = () =>
requestAnimationFrame(() => objViewer.Refit());
@if (Viewer.IsSearchEnabled)
{
<text>
searchBar = $('#searchBarMount').doconutSearchBar({
docId: 'ctlDoc',
getRequestParams: () => ({ token: currentToken }),
onLayout: refitViewer
});
searchBar.attach(objViewer);
</text>
}
@if (Viewer.IsAnnotationEnabled)
{
<text>
annBar = $('#annBarMount').doconutAnnotationBar({
docId: 'ctlDoc',
getRequestParams: () => ({ token: currentToken }),
onLayout: refitViewer
});
annBar.attach(objViewer);
</text>
}
document.getElementById('openSearch').addEventListener('click', () => {
if (!searchBar) return;
searchBar.isOpen() ? searchBar.close() : searchBar.open();
});
document.getElementById('openAnnotations').addEventListener('click', () => {
if (!annBar) return;
annBar.isOpen() ? annBar.close() : annBar.open();
});
</script>Cả hai thành phần nhúng đều tạo DOM Ribbon riêng. Search chứa các nhóm Find, Options và Results. Annotation chứa các công cụ tạo nội dung, điều khiển kiểu, hành động lưu và các hành động xuất/ảnh tùy chọn. Các thanh cung cấp các phương thức open(), close(), reset(), và isOpen(); luôn gọi attach(objViewer) một lần sau khi tạo chúng.
Ví dụ trên bỏ qua các callback host tùy chọn và các endpoint xuất/ảnh của Annotation để giữ khởi động tối thiểu. Xem Tìm kiếm và Chú thích để có cài đặt đầy đủ cho từng tính năng, hoặc Chủ đề Tùy chỉnh để tạo kiểu hoặc thay thế thanh công cụ Viewer thuộc host.
Mở tài liệu
Phía server có một endpoint: dịch vụ Viewer được tiêm mở tài liệu và trả về một token phiên.
app.MapPost("/api/open", async (Viewer viewer) =>
{
// The token is opaque — hand it to the widget, never log or persist it.
string token = await viewer.OpenDocumentAsync("wwwroot/files/Sample.pdf");
return Results.Ok(new { token });
});Client lấy token đó và truyền cho widget bằng objViewer.View(token):
fetch('/api/open', { method: 'POST' })
.then(resp => resp.json())
.then(data => {
currentToken = data.token;
objViewer.View(currentToken);
});Đóng tài liệu
Gọi objViewer.Close() khi người dùng rời khỏi viewer hoặc mở một tài liệu thay thế. Trong quy trình làm việc do server điều khiển, viewer.CloseDocument(token) ngay lập tức xóa phiên cache, giải phóng engine render, xóa dấu bảo mật và thu hồi token. Thời gian hết hạn trượt cuối cùng sẽ thực hiện cùng việc dọn dẹp, nhưng việc đóng một cách rõ ràng được khuyến nghị cho các tài liệu lớn.
Luồng yêu cầu hoàn chỉnh là:
AddDoconut + middleware
-> render CSS/scripts and mount div
-> initialize docViewer
-> OpenDocumentAsync
-> return opaque token
-> objViewer.View(token)
-> page/search/annotation requests
-> Close / CloseDocumentCân nhắc token như một chứng chỉ bearer: không bao giờ ghi log nó, không bao giờ lưu trữ nó, chỉ truyền nó cho widget. Nó xác định một phiên tài liệu đang hoạt động trên server và sẽ không hoạt động khi phiên đó hết hạn — mở lại tài liệu để nhận token mới.
Chạy nó
Đặt một file PDF tại wwwroot/files/Sample.pdf, chạy dotnet run, và mở trang chứa widget. Trang đầu tiên sẽ được hiển thị trong viewer, với một panel thumbnail ở bên trái. Nếu không, xem Khắc phục sự cố.
Những gì bạn nhận được khi không có giấy phép
Một giấy phép thiếu sẽ không gây lỗi. Viewer vẫn hiển thị bình thường, nhưng mỗi trang sẽ có watermark đánh giá. Xem Cài đặt giấy phép để biết Doconut tìm giấy phép như thế nào và những gì sẽ thay đổi khi có giấy phép.
Trang này có hữu ích không?