راهاندازی مجوز
محل جستجوی Doconut برای فایل مجوز شما
بدون داشتن مجوز، Doconut همچنان اسناد را رندر میکند — هر صفحه فقط دارای واترمارک ارزیابی است. این صفحه چهار روش ارائه مجوز را پوشش میدهد و ترتیب دقیق اولویتها را زمانی که بیش از یک منبع تنظیم شده باشد، توضیح میدهد.
مجوز یکبار، در زمان AddDoconut() بارگذاری میشود. این یک تغییر نسبت به کتابخانه قبلی .NET Standard است، که در آن مجوز به یک نمونه Viewer داده میشد یا از طریق فراخوانیهای استاتیک Viewer.DoconutLicense(...) / Viewer.SetLicensePlugin(...) تنظیم میشد. این متدها در این نسخه مکانیزم استارتاپ نیستند — برای جزئیات به راهنمای مهاجرت مراجعه کنید.
چهار روش برای ارائه مجوز
چهار روش وجود دارد: سه منبع صریح در DoconutOptions — یک جریان، محتوای خام، یا مسیر فایل — بهعلاوه کشف خودکار زمانی که هیچکدام تنظیم نشده باشند. وقتی بیش از یک منبع تنظیم شده باشد، ترتیب اولویت دقیقاً به این شکل است:
LicenseStream بر LicenseContent بر LicensePath بر جستجوی خودکار.
بر اساس مسیر
LicensePath دقیقاً همانطور که داده شده به File.Exists پاس داده میشود. یک مسیر نسبی نسبت به دایرکتوری کاری فعلی فرایند حل میشود — نه پوشه پروژه شما، و نه پوشهای که Program.cs در آن قرار دارد. اگر مسیر حل نشود، Doconut خطا نمیاندازد و بهجای جستجوی خودکار بازنگشت نمیکند — بهسادگی هیچ مجوزی بارگذاری نمیشود و Viewer واترمارک میزند. جستجوی خودکار فقط زمانی اجرا میشود که هیچیک از LicensePath، LicenseContent یا LicenseStream تنظیم نشده باشد. فایلهای مجوز per‑plugin در همان پوشه (Doconut.Viewer.<Capability>.lic) همراه با آن خوانده میشوند، بنابراین LicensePath و AddPlugin<...>() زمانی که مجوزهای افزونه در کنار مجوز پایه قرار دارند، با هم کار میکنند.
یک مسیر مطلق را ترجیح دهید (برای مثال ساخته شده از IWebHostEnvironment.WebRootPath یا AppContext.BaseDirectory)، یا بهطور کامل LicensePath را حذف کنید و به کشف خودکار زیر تکیه کنید.
builder.Services.AddDoconut(options =>
{
options.LicensePath = Path.Combine(AppContext.BaseDirectory, "wwwroot", "Doconut.Viewer.lic");
});بر اساس جریان
LicenseStream یکبار در زمان استارتاپ خوانده میشود — مفید زمانی که مجوز از یک مخزن مخفی بهجای یک فایل روی دیسک میآید.
// ترتیب: LicenseStream > LicenseContent > LicensePath > جستجوی خودکار.
builder.Services.AddDoconut(options =>
{
options.LicenseStream = licenseStream;
});بر اساس محتوا
LicenseContent متن مجوز را بهصورت مستقیم میپذیرد — از یک متغیر محیطی، پایگاه داده، یا مدیر مخفی:
// XML مجوز از یک پایگاه داده، متغیر محیطی یا مدیر مخفی —
// فایلی روی دیسک نیست. فقط توسط LicenseStream پیشی میگیرد.
builder.Services.AddDoconut(options =>
{
options.LicenseContent = Environment.GetEnvironmentVariable("DOCONUT_LICENSE") ?? "";
});کشف خودکار
هیچیک از سه منبع صریح را پیکربندی نکنید و Doconut خود بهصورت خودکار مجوز را جستجو میکند:
// هیچچیزی پیکربندی نشود، و Doconut خود بهصورت خودکار مجوز را در این دو پوشه جستجو میکند، فقط در این دو پوشه:
// 1. {CurrentDirectory}/wwwroot
// 2. {AppContext.BaseDirectory}/wwwroot (wwwroot داخل پوشه خروجی ساخت)
// ابتدا به دنبال Doconut.lic میگردد، سپس Doconut.Viewer.lic، بهعلاوه هر مجوز مربوط به قابلیت خاص
// فایلهای Doconut.Viewer.<Capability>.lic که در کنار آن قرار دارند.
builder.Services.AddDoconut();پوشههای جستجو به ترتیب، و نام فایلهایی که در هر کدام بررسی میشوند:
1. {CurrentDirectory}/wwwroot
2. {AppContext.BaseDirectory}/wwwroot
Filenames (checked in each folder above, in order):
Doconut.lic — base viewer license (checked first)
Doconut.Viewer.lic — base viewer license
Doconut.Viewer.<Capability>.lic — per-capability license, alongside the base licenseهیچ چیزی خارج از پوشه wwwroot خوانده نمیشود: یک فایل .lic در خود پوشه خروجی یا در wwwroot/lib نادیده گرفته میشود.
اگر پیشتر یک List<string> از مسیرهای مجوز را به سازنده Viewer پاس دادهاید — یکی برای هر قابلیت — آن فایلهای همراه را در کنار Doconut.Viewer.lic نگه دارید و بگذارید کشف خودکار آنها را پیدا کند. گزینهای برای لیست مسیرها در DoconutOptions وجود ندارد.
کپی کردن مجوز به پوشه خروجی شما
زمانی که فرآیند از پوشهٔ پروژه اجرا نمیشود — مثلاً یک برنامهٔ منتشرشده، IIS، یک کانتینر یا یک تست رانر — اولین جستجو ناموفق میماند و دومین مسیر {AppContext.BaseDirectory}/wwwroot باید فایل را پیدا کند. برنامهٔ تستی خود SDK در هر ساخت با این هدفمقصد MSBuild، مجوزها را به آنجا کپی میکند:
<Target Name="CopyLicensesToOutput" AfterTargets="Build">
<ItemGroup>
<DoconutLicenseFiles Include="$(MSBuildProjectDirectory)\wwwroot\*.lic" />
<StaleOutputLicenses Include="$(OutDir)wwwroot\*.lic" />
</ItemGroup>
<!-- ابتدا حذف میشود، تا تغییر نام یا حذف یک .lic در wwwroot نیز از خروجی حذف شود. -->
<Delete Files="@(StaleOutputLicenses)" />
<Copy SourceFiles="@(DoconutLicenseFiles)" DestinationFolder="$(OutDir)wwwroot" />
</Target>مقصد باید $(OutDir)wwwroot باشد: یک فایل .lic که به ریشهٔ خروجی کپی شود، هرگز توسط جستجوی خودکار پیدا نمیشود. مثالهای LicensePath در این صفحه همگی به همین مکان اشاره میکنند.
فایلهای
.licرا از کنترل نسخه خارج نگه دارید — آنها را همراه با برنامه مستقر کنید یا مجوز را از طریقLicenseContentیاLicenseStreamاز مخزن محرمانهٔ خود تزریق کنید.
چه اتفاقی میافتد بدون مجوز
یک مجوز گمشده خطایی نمیاندازد. AddDoconut() با موفقیت اجرا میشود، برنامه راهاندازی میشود و ویور اجرا میگردد — اما هر صفحه دارای واترمارک ارزیابی است و هیچ قابلیت اختیاریای فعال نمیشود.
فایل مجوزی که پیدا میشود اما رد میشود متفاوت است. امضای نامعتبر، دستکاری، قرار در لیست سیاه یا ساختی خارج از بازهٔ نسخهٔ مجوز باعث میشود OpenDocumentAsync خطای LicenseException با License.RejectionMessage پرتاب کند. مجوزی که تاریخاش منقضی شده اما پیام رد ندارد، همچنان در حالت واترمارک ادامه میدهد.
افزونهها به قابلیتها نیاز دارند
ثبت یک افزونه بدون داشتن حقالامتیاز مربوطه متفاوت است: برای یک مجوز گمشده، فایل TRIAL قدیمی یا یک مجوز تجاری که آن قابلیت را ندهد، AddDoconut() خطای InvalidOperationException میاندازد، بنابراین برنامه راهاندازی نمیشود. برای مثال، ثبت افزونهٔ Converter بدون داشتن مجوزی که Converter را اعطا کند:
InvalidOperationException: The Converter plugin is registered via AddPlugin but no active
license grants Converter. Remove the AddPlugin<...>() call or install a license (or
trial/demo) that includes Converter.پیام بهصورت مستقیم راه حل را میگوید: یا فراخوانی options.AddPlugin<...>() برای آن افزونه را حذف کنید، یا یک مجوز تجاری یا یک مجوز موقت/دموی فعال (NFR) که این قابلیت را بدهد نصب کنید. ثبتنامهای موقت اجازه میدهند پس از تاریخ انقضا نیز باقی بمانند تا برنامهٔ پیشپیکربندیشده بتواند بهصورت تدریجی کاهش یابد، نه اینکه در زمان راهاندازی مجدد کرش کند؛ پس از انقضا، قابلیتهایشان همچنان لغو میشود.
تأیید مجوز بارگذاری شده
از IDoconutLicenseService، همان منبع حقیقتی که SDK از آن استفاده میکند، برای ارائهٔ یک نقطهٔ پایانی تشخیص هویتدار یا برای کنترل پرچمهای ویژگی استفاده کنید. محتویات یا کلیدهای مجوز را برنگردانید.
app.MapGet("/api/doconut/license", (IDoconutLicenseService license) => Results.Ok(new
{
viewer = license.IsViewerLicensed || license.IsTemporary,
temporary = license.IsTemporary,
search = license.IsCapabilityGranted(LicenseCapability.Search),
annotation = license.IsCapabilityGranted(LicenseCapability.Annotation),
converter = license.HasConverter,
dicom = license.HasDicom
}));مجوز در زمان ثبت AddDoconut() خوانده میشود. ResetLicense در حال حاضر یک ویژگی سازگاری است که مسیر بارگذاری مجدد فعال ندارد، بنابراین جایگزینی فایل مجوز نیاز به راهاندازی مجدد برنامه دارد.
ماتریس عیبیابی
| علامت | دلیل محتمل | بررسی |
|---|---|---|
| Viewer کار میکند اما هر صفحه دارای واترمارک است | هیچ مجوزی بارگذاری نشده یا مجوز منقضی شده است | سرویس IDoconutLicenseService را حل کنید؛ مسیر خروجی و مسیر کاری فرآیند را بررسی کنید |
AddDoconut() برای یک افزونه خطا میدهد | مجوز آن قابلیت افزونه را اعطا نمیکند | متد IsCapabilityGranted(...) را بررسی کنید و ثبتنامهایی که خریداری نکردهاید حذف کنید |
| مسیر نسبی پیکربندیشده بهصورت محلی کار میکند اما در IIS/کانتینر کار نمیکند | مسیر کاری فرآیند تغییر کرده است | از AppContext.BaseDirectory یا مسیر مطلق استفاده کنید |
فایل .lic جایگزین هیچ اثری ندارد | سرویس تکنمونهٔ مجوز قبلاً ایجاد شده بود | برنامه را مجدداً راهاندازی کنید |
OpenDocumentAsync خطای LicenseException میاندازد | امضا، دامنه، بازهٔ نسخه، لیست سیاه یا دروازهٔ زمان اجرا افزونه مجوز را رد کردهاند | پیام استثنا/رد را بدون نمایش به مشتریان غیرقابل اعتماد بخوانید |
| مجوز بر پایه قابلیت قبلاً کار میکرد اما اکنون نه | کد قدیمی مسیرهای صریح مجوز را به سازندهٔ Viewer میداد | فایلهای .lic همراه را در کنار Doconut.Viewer.lic قرار دهید و اجازه دهید کشف خودکار آنها را بارگذاری کند |
مراحل بعدی
آیا این صفحه مفید بود؟