라이선스 설정

Doconut이 라이선스 파일을 찾는 위치

라이선스가 없더라도 Doconut은 문서를 렌더링합니다 — 각 페이지에 평가용 워터마크가 표시됩니다. 이 페이지에서는 라이선스를 제공하는 네 가지 방법과 여러 개가 설정된 경우 정확한 우선 순위를 설명합니다.

라이선스는 한 번, AddDoconut() 동안 로드됩니다. 이는 이전 .NET Standard 라이브러리와 달리, 라이선스를 Viewer 인스턴스에 전달하거나 정적 Viewer.DoconutLicense(...) / Viewer.SetLicensePlugin(...) 호출을 통해 설정하던 방식과 다릅니다. 이 릴리스에서는 해당 메서드들이 시작 메커니즘이 아니므로, 마이그레이션 가이드를 참조하십시오.

라이선스를 제공하는 네 가지 방법

DoconutOptions에 명시된 세 가지 소스(스트림, 원시 콘텐츠, 파일 경로)와 설정되지 않았을 때 자동 검색을 포함하여 총 네 가지가 있습니다. 여러 개가 설정된 경우 정확한 우선 순위는 다음과 같습니다:

LicenseStream > LicenseContent > LicensePath > auto-search

경로별

LicensePath는 그대로 File.Exists에 전달됩니다. 상대 경로는 프로세스의 현재 작업 디렉터리를 기준으로 해석됩니다 — 프로젝트 폴더가 아니라 Program.cs 파일이 위치한 폴더도 아닙니다. 경로가 해석되지 않으면 Doconut은 예외를 발생시키지 않으며 자동 검색으로 대체되지도 않습니다 — 라이선스를 로드하지 않고 뷰어에 워터마크가 표시됩니다. 자동 검색은 LicensePath, LicenseContent, LicenseStream 중 어느 것도 설정되지 않았을 때만 실행됩니다. 동일 폴더에 있는 플러그인별 라이선스 파일(Doconut.Viewer.<Capability>.lic)도 함께 읽히므로, 플러그인 라이선스가 기본 라이선스 옆에 있을 경우 LicensePath와 AddPlugin<...>()가 함께 작동합니다.

절대 경로를 사용하는 것이 좋습니다(IWebHostEnvironment.WebRootPath 또는 AppContext.BaseDirectory에서 생성된 경우 등). 또는 LicensePath를 완전히 생략하고 아래의 자동 검색에 의존할 수 있습니다.

csharp
builder.Services.AddDoconut(options =>
{
    options.LicensePath = Path.Combine(AppContext.BaseDirectory, "wwwroot", "Doconut.Viewer.lic");
});

스트림별

LicenseStream은 시작 시 한 번 읽히며, 라이선스가 디스크 파일이 아닌 비밀 저장소에서 제공될 때 유용합니다.

csharp
// 우선 순위: LicenseStream > LicenseContent > LicensePath > auto-search.
builder.Services.AddDoconut(options =>
{
    options.LicenseStream = licenseStream;
});

콘텐츠별

LicenseContent는 라이선스 텍스트 자체를 받아들입니다 — 환경 변수, 데이터베이스 또는 비밀 관리자에서 가져올 수 있습니다:

csharp
// 데이터베이스, 환경 변수 또는 비밀 관리자에서 가져온 라이선스 XML —
// 디스크에 파일이 없습니다. LicenseStream에 의해서만 우선합니다.
builder.Services.AddDoconut(options =>
{
    options.LicenseContent = Environment.GetEnvironmentVariable("DOCONUT_LICENSE") ?? "";
});

자동 검색

세 가지 명시적 소스 중 어느 것도 설정하지 않으면, Doconut이 직접 라이선스를 검색합니다:

csharp
// 아무것도 설정하지 않으면, Doconut이 라이선스를 직접 검색합니다. 이 두 폴더에서만:
//   1. {CurrentDirectory}/wwwroot
//   2. {AppContext.BaseDirectory}/wwwroot   (빌드 출력 폴더 안의 wwwroot)
// 먼저 Doconut.lic을 찾고, 그 다음 Doconut.Viewer.lic을 찾으며, 각 기능별
// Doconut.Viewer.<Capability>.lic 파일을 그 옆에 찾습니다.
builder.Services.AddDoconut();
text
1. {CurrentDirectory}/wwwroot
2. {AppContext.BaseDirectory}/wwwroot

파일 이름 (위 각 폴더에서 순서대로 확인):
  Doconut.lic                          — 기본 뷰어 라이선스 (첫 번째로 확인됨)
  Doconut.Viewer.lic                   — 기본 뷰어 라이선스
  Doconut.Viewer.<Capability>.lic      — 기능별 라이선스, 기본 라이선스와 함께

wwwroot 폴더 외부에 있는 파일은 읽지 않습니다. 출력 폴더 자체에 있거나 wwwroot/lib에 있는 .lic 파일은 무시됩니다.

이전에 Viewer 생성자에 라이선스 경로 List<string>(기능당 하나)를 전달한 경우, 해당 파일들을 Doconut.Viewer.lic 옆에 두어 자동 검색이 찾아가도록 하세요. DoconutOptions에는 경로 목록 옵션이 없습니다.

라이선스를 출력 폴더에 복사하기

프로세스가 프로젝트 폴더에서 실행되지 않을 때 — 배포된 앱, IIS, 컨테이너, 테스트 러너 등 — 첫 번째 탐색이 실패하고 두 번째 탐색인 {AppContext.BaseDirectory}/wwwroot가 파일을 찾아야 합니다. SDK 자체 테스트 앱은 매 빌드마다 이 MSBuild 타깃을 사용해 라이선스를 해당 위치에 복사합니다:

xml
<Target Name="CopyLicensesToOutput" AfterTargets="Build">
  <ItemGroup>
    <DoconutLicenseFiles Include="$(MSBuildProjectDirectory)\wwwroot\*.lic" />
    <StaleOutputLicenses Include="$(OutDir)wwwroot\*.lic" />
  </ItemGroup>
  <!-- 먼저 삭제합니다. 이렇게 하면 wwwroot에서 .lic 파일을 이름을 바꾸거나 제거할 때도 출력에서 제거됩니다. -->
  <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 플러그인을 등록하는 경우:

text
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가 사용하는 동일한 진실의 원천으로, 인증된 진단 엔드포인트를 제공하거나 기능 플래그를 제어하는 데 사용됩니다. 라이선스 내용이나 키를 반환하지 마세요.

csharp
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는 현재 활성 재로드 경로가 없는 호환성 속성으로, 라이선스 파일을 교체하려면 애플리케이션을 재시작해야 합니다.

문제 해결 매트릭스

증상가능한 원인확인 방법
뷰어는 작동하지만 모든 페이지에 워터마크가 표시됨라이선스가 로드되지 않았거나 캘린더가 만료된 라이선스IDoconutLicenseService 해결; 출력 디렉터리와 프로세스 작업 디렉터리 확인
AddDoconut()가 플러그인에서 예외 발생라이선스에 해당 플러그인 기능이 부여되지 않음IsCapabilityGranted(...) 확인 및 구매하지 않은 등록 제거
구성된 상대 경로가 로컬에서는 작동하지만 IIS/컨테이너에서는 작동하지 않음프로세스 작업 디렉터리가 변경됨AppContext.BaseDirectory 또는 절대 경로 사용
교체된 .lic 파일이 효과가 없음싱글톤 라이선스 서비스가 이미 생성됨애플리케이션 재시작
OpenDocumentAsync가 LicenseException을 발생서명, 도메인, 버전 창, 블랙리스트, 또는 플러그인 런타임 게이트가 라이선스를 거부함예외/거부 메시지를 읽되 신뢰할 수 없는 클라이언트에 노출하지 않음
기능별 라이선스가 이전에는 작동했지만 현재는 작동하지 않음이전 코드가 Viewer 생성자에 명시적인 라이선스 경로를 전달함동반 .lic 파일을 Doconut.Viewer.lic 옆으로 이동하고 자동 검색이 로드하도록 함

다음 단계

  • 라이선스 — 기능, 라이선스 등급, 그리고 런타임에 로드된 내용을 확인하는 방법.
  • 문제 해결 — 워터마크, 거부된 라이선스, 그리고 기능 오류.

이 페이지가 도움이 되었나요?