เริ่มต้นอย่างรวดเร็ว
เรนเดอร์เอกสารแรกของคุณในไม่กี่นาที
บทแนะนำนี้นำแอป ASP.NET Core จากไฟล์ Program.cs ว่างเปล่าไปสู่การแสดงเอกสารในเบราว์เซอร์: การลงทะเบียนเซิร์ฟเวอร์, แพ็กเกจ Viewer ครบชุด (แถบเครื่องมือ Viewer, การเมานท์ Viewer, และริบบิ้น Search/Annotation ที่เป็นตัวเลือก), การอ้างอิงทรัพยากร, การเริ่มต้นไคลเอนต์, การเปิดเอกสาร, และการดำเนินการ.
การตั้งค่าเซิร์ฟเวอร์
AddDoconut() ลงทะเบียนบริการ; UseDoconutResources() และ UseDoconut() เชื่อมต่อ middleware. การเรียก resources ต้องมาก่อน. การเรียก session ก็จำเป็นเช่นกัน — ระบบความปลอดภัยเอกสารเริ่มต้นของ Doconut ตรวจสอบคำขอแต่ละหน้าต่อสถานะ session ของ ASP.NET. ได้ลงทะเบียน Doconut ไว้แล้วหรือยังในระหว่าง การติดตั้ง? ข้ามไปยังส่วนถัดไป.
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();สำหรับการจัดวางเส้นทางแบบการผลิต, ให้แมป middleware ของเอกสารไปยังสาขาที่ระบุอย่างชัดเจนและรักษาการตั้งค่าเส้นทางสี่ค่าให้สอดคล้องกัน:
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 เป็นค่าการประสาน; มันไม่ได้แมปสาขา ASP.NET Core ด้วยตัวเอง. ในตัวอย่างนี้โฮสต์แมป /doconut, ดังนั้นไคลเอนต์ต้องใช้ BasePath: '/doconut'. ResourcesPath ให้บริการบันเดิลที่ฝังอยู่ที่ /doconut-res, และเส้นทางทรัพยากรรูปภาพของวิดเจ็ตจึงเป็น ResPath: '/doconut-res/images'.
เพิ่มตัวดูเอกสารลงในหน้า
Viewer เป็นแกนหลักที่จำเป็นของหน้า. พื้นผิวการเรนเดอร์ของมันใช้ div สองชั้นซ้อนกัน:
<div id="divDocViewer">
<div id="div_ctlDoc"></div>
</div>พิจารณาแถบเครื่องมือ, การเมานท์โมดูล, และพื้นผิว Viewer เป็นการจัดองค์ประกอบหน้าเดียว. Search และ Annotation แทรกริบบิ้นที่ฝังอยู่ลงในการเมานท์ที่เป็นตัวเลือก, แต่โมดูลเหล่านั้นไม่มีการทำงานแบบอิสระ: พวกมันจะผูกกับ Viewer บนหน้าเดียวกันเสมอ. ใช้ลำดับเดียวกับ Doconut.TestApp และ 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>อ้างอิงทรัพยากรตัวดูเอกสาร
ใน Razor view, เซอร์วิส Viewer ที่ฉีดเข้ามาจะสร้างแท็ก <link> และ <script> ของตัวดูเอกสารตามลำดับการพึ่งพา — วิดเจ็ตเป็นปลั๊กอิน jQuery, ดังนั้นต้องโหลด jQuery ก่อนสคริปต์ของ 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
}))สำหรับแพคเกจ Viewer ครบชุด, ให้ร้องขอทรัพยากร Viewer และโมดูลพร้อมกัน:
@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 และ IncludeViewerScripts เป็นแฟล็กหลักที่จำเป็น. อย่าเผยแพร่ตัวอย่างริบบิ้น Search หรือ Annotation โดยไม่มีพวกมัน, การเมานท์ Viewer, และอินสแตนซ์ docViewer. ReferenceCss และ ReferenceScripts จะละเว้นทรัพยากรของโมดูลที่เป็นตัวเลือกเมื่อใบอนุญาตปัจจุบันไม่ให้สิทธิ์; Viewer หลักยังคงเริ่มทำงาน.
เริ่มต้นตัวดูเอกสาร
วิดเจ็ตฝั่งไคลเอนต์เป็นปลั๊กอิน jQuery. นี่คือชุดตัวเลือกการเริ่มต้นที่เป็นจริงและขั้นต่ำ (ไม่ใช่โค้ดเทียม):
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);
}
});รูปแบบการเขียนตัวอักษรของตัวเลือกผสมกันจริง ๆ — showThumbs, autoLoad, และ pageZoom ใช้ camelCase, แต่ FitType, BasePath, และ ResPath ใช้ PascalCase. ไม่มีกฎที่สอดคล้อง; หากเขียนรูปแบบผิด ตัวเลือกจะถูกละเลยโดยไม่มีการแจ้ง (วิดเจ็ตจะกลับไปใช้ค่าเริ่มต้นแทนการโยนข้อผิดพลาด).
รวมแพคเกจ Viewer ที่สมบูรณ์
ทั้งสองแอปอ้างอิงของ .NET 6 จะติดตั้งส่วนต่อไปนี้พร้อมกันในหน้าเดียว:
| ส่วนของแพคเกจ | ความต้องการ | วิธีการเชื่อมต่อ |
|---|---|---|
ทรัพยากร Viewer, การเมานท์, และ objViewer | จำเป็น | เรนเดอร์เอกสารหลัก |
| แถบเครื่องมือ Viewer | จำเป็นในโครงสร้างอ้างอิง | มาร์กอัปโฮสต์; ปุ่มเรียก objViewer เดียวกัน |
| ริบบิ้นการค้นหา | โมดูลที่มีใบอนุญาต, ไม่บังคับ | doconutSearchBar(...).attach(objViewer) |
| ริบบิ้นคำอธิบาย | โมดูลที่มีใบอนุญาต, ไม่บังคับ | doconutAnnotationBar(...).attach(objViewer) |
แม้ว่าแถบเครื่องมือ Viewer หลักจะเป็นมาร์กอัปของโฮสต์, มันถูกติดตั้งพร้อมกับ Viewer และไม่ควรอธิบายเป็นคอนโทรลแยก. สิ่งนี้ทำให้การจัดวาง, ป้ายกำกับ, ไอคอน, และกฎการอนุญาตอยู่ภายใต้การควบคุมของแอปพลิเคชันของคุณในขณะที่ทุกปุ่มทำงานกับอินสแตนซ์ 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>แถบเครื่องมืออ้างอิงเต็มยังคัดลอกไฟล์ wwwroot/js/viewerToolbar.js ไปยังแอปพลิเคชันโฮสต์เพื่อใช้สำหรับการหมุน, แถบภาพย่อ, พิมพ์, เต็มจอ, การจัดวาง, และตัวช่วยสถานะปุ่ม. โหลดไฟล์โฮสต์นั้นหลังจาก Viewer.ReferenceScripts(...). เก็บตัวช่วยและมาร์กอัป <nav id="toolbar"> ของมันไว้ด้วยกันเมื่อคัดลอกการสาธิตเต็ม.
รักษาลำดับการเริ่มต้นแพคเกจที่ใช้โดยทั้งสองแอปอ้างอิง:
- สร้าง CSS สำหรับ Viewer และโมดูลที่มีใบอนุญาต.
- เรนเดอร์แถบเครื่องมือ Viewer, การเมานท์ Search/Annotation, และการเมานท์ Viewer พร้อมกัน.
- สร้างสคริปต์สำหรับ Viewer และโมดูลที่มีใบอนุญาต.
- โหลดไฟล์
viewerToolbar.jsของแอปพลิเคชันโฮสต์. - เริ่มต้น
docViewerและเก็บobjViewerที่ได้. - เริ่มต้นริบบิ้น Search หรือ Annotation แต่ละอันที่มีใบอนุญาต.
- เรียก
attach(objViewer)บนทุกริบบิ้น. - เปิดเอกสารและเก็บโทเคนของมันสำหรับคำขอของ Viewer และโมดูล.
Doconut.TestApp.Distributed รักษาการจัดองค์ประกอบ UI นี้อย่างแม่นยำและตัวช่วยแถบเครื่องมือ Viewer เดียวกัน. ค่า access ที่เพิ่มเข้ามาและการตั้งค่าการลองใหม่แบบเรนเดอร์แบบอะซิงโครนัสเป็นของการส่งข้อมูลแบบกระจาย; พวกมันไม่เปลี่ยนวิธีการประกอบ Viewer, แถบเครื่องมือ, หรือริบบิ้น.
การป้องกันฝั่งเซิร์ฟเวอร์มีความสำคัญ: เมื่อความสามารถแบบตัวเลือกไม่พร้อมใช้งาน, สคริปต์ของมันจะไม่ถูกสร้าง, ดังนั้นฟังก์ชันปลั๊กอิน jQuery ของมันจะไม่มีอยู่.
<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>ทั้งสองคอมโพเนนท์ที่ฝังอยู่สร้าง DOM ของริบบิ้นของตนเอง. Search มีกลุ่ม Find, Options, และ Results. Annotation มีเครื่องมือการเขียน, การควบคุมสไตล์, การบันทึก, และการส่งออก/รูปภาพที่เป็นตัวเลือก. แถบเหล่านี้เปิดเผยเมธอด open(), close(), reset(), และ isOpen(); ควรเรียก attach(objViewer) หนึ่งครั้งหลังจากสร้าง.
ตัวอย่างด้านบนละเว้นการเรียกกลับของโฮสต์ที่เป็นตัวเลือกและจุดสิ้นสุดการส่งออก/รูปภาพของ Annotation เพื่อให้การเริ่มต้นเป็นอย่างน้อยที่สุด. ดู การค้นหา และ คำอธิบาย สำหรับการตั้งค่าฟีเจอร์ที่สมบูรณ์, หรือ ธีมที่กำหนดเอง เพื่อสไตล์หรือแทนที่แถบเครื่องมือ Viewer ที่เป็นของโฮสต์.
เปิดเอกสาร
ฝั่งเซิร์ฟเวอร์มีจุดเชื่อมต่อเดียว: เซอร์วิส Viewer ที่ฉีดเข้ามาจะเปิดเอกสารและคืนค่าโทเคนเซสชัน.
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 });
});ไคลเอนต์ดึงโทเคนนั้นและส่งให้วิดเจ็ตด้วย objViewer.View(token):
fetch('/api/open', { method: 'POST' })
.then(resp => resp.json())
.then(data => {
currentToken = data.token;
objViewer.View(currentToken);
});ปิดเอกสาร
เรียก objViewer.Close() เมื่อผู้ใช้ออกจากตัวดูหรือเปิดเอกสารทดแทน. ในเวิร์กโฟลว์ที่ควบคุมโดยเซิร์ฟเวอร์, viewer.CloseDocument(token) จะลบเซสชันที่แคชไว้ทันที, ปิดการทำงานของเอนจินการเรนเดอร์, ลบเครื่องหมายความปลอดภัย, และเพิกถอนโทเคน. การหมดอายุแบบเลื่อนจะทำความสะอาดเช่นเดียวกันในภายหลัง, แต่การปิดอย่างชัดเจนแนะนำสำหรับเอกสารขนาดใหญ่.
กระบวนการร้องขอที่สมบูรณ์คือ:
AddDoconut + middleware
-> render CSS/scripts and mount div
-> initialize docViewer
-> OpenDocumentAsync
-> return opaque token
-> objViewer.View(token)
-> page/search/annotation requests
-> Close / CloseDocumentถือโทเคนเหมือนข้อมูลประจำตัวแบบ bearer: อย่าบันทึก, อย่าจัดเก็บ, ส่งให้วิดเจ็ตเท่านั้น. มันระบุเซสชันเอกสารที่ใช้งานอยู่บนเซิร์ฟเวอร์และจะหยุดทำงานเมื่อเซสชันนั้นหมดอายุ — เปิดเอกสารใหม่เพื่อรับโทเคนใหม่.
รันมัน
วางไฟล์ PDF ที่ wwwroot/files/Sample.pdf, รัน dotnet run, แล้วเปิดหน้าที่โฮสต์วิดเจ็ต. หน้าแรกจะเรนเดอร์ในตัวดูพร้อมแผงภาพย่อทางซ้าย. หากไม่แสดง, ดูที่ การแก้ไขปัญหา.
สิ่งที่คุณจะได้โดยไม่มีใบอนุญาต
การไม่มีใบอนุญาตจะไม่ทำให้เกิดข้อผิดพลาด. ตัวดูจะเรนเดอร์ตามปกติ, แต่ทุกหน้าจะมีลายน้ำการประเมิน. ดูที่ การตั้งค่าใบอนุญาต เพื่อทราบว่า Doconut ค้นหาใบอนุญาตอย่างไรและอะไรจะเปลี่ยนเมื่อพบ.
หน้านี้เป็นประโยชน์หรือไม่?