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