뷰어 작동 방식

문서 요청 라이프사이클

Doconut는 ASP.NET Core 미들웨어를 통해 페이지화된 이미지로 문서를 렌더링합니다. 라이프사이클(열기, 토큰, 페이지 요청, 닫기)을 이해하면 오류 메시지를 포함해 관찰하는 거의 모든 동작을 설명할 수 있습니다.

세 가지 동작 요소

  • Viewer — 주입하는 공개 서비스입니다. 문서를 열고 세션 토큰을 반환합니다.
  • 문서 세션 — 로드된 문서를 보관하는 서버 측 객체이며, IMemoryCache의 토큰을 키로 사용합니다.
  • Doconut 미들웨어 — UseDoconut()에 의해 추가되며, 브라우저 위젯이 만드는 모든 요청(pages, thumbnails, search, annotations, …)에 응답하고 항상 토큰으로 인증됩니다.

Viewer은 무상태 — 설계상

Viewer은 sealed이며, 요청당 문서 상태를 보관하지 않고, 의도적으로 IDisposable을 구현하지 않습니다. 세션은 세션 관리자에서 독립적으로 존재하며 캐시 만료 또는 명시적인 CloseDocument(token)에 의해 정리됩니다.

이제 직접 인스턴스를 만들 필요가 없습니다. AddDoconut()은 이를 transient 서비스로 등록합니다; 필요할 때마다 주입하십시오:

csharp
app.MapPost("/api/open", async (string fileName, Viewer viewer) =>
{
    var token = await viewer.OpenDocumentAsync($"files/{fileName}");
    return Results.Content(token, "text/plain");
});

MVC 애플리케이션에서는 생성자 매개변수로 받아 사용하고, Razor 뷰에서는 @inject Doconut.Viewer Viewer을 사용합니다. Viewer 인스턴스에 대한 애플리케이션 전용 캐시는 더 이상 필요하지 않으며—그렇지 않아야 합니다—왜냐하면 캐시할 가치가 있는 것이 없기 때문입니다.

OpenDocumentAsync 내부에서 일어나는 일

  1. License gate. 거부되었거나 버전이 만료된 라이선스(블랙리스트에 올랐거나 변조되었거나 라이선스 업데이트 기간 외의 빌드)는 즉시 LicenseException을 발생시키며, 거부 사유를 메시지로 제공합니다 — 존재하지만 유효하지 않은 라이선스에 대해서는 열기가 조용히 저하되지 않습니다. 캘린더가 만료된 Temporary 또는 구독 라이선스는 예외이며, 예외를 발생시키지 않고 워터마크로 저하됩니다.
  2. Session creation. 뷰어 팩토리는 파일 확장자에 맞는 포맷 뷰어를 선택하고 문서를 로드합니다(렌더링 파이프라인 참조). 세션은 새 GUID 토큰과 함께 IMemoryCache에 저장되며 슬라이딩 만료를 가집니다 — DocOptions.TimeOut 분, 기본값 60분. 각 페이지 요청마다 타이머가 재설정됩니다.
  3. Security registration. 기본값인 UnsafeMode = false을 사용하면 토큰이 호출자의 ASP.NET 세션에 바인딩됩니다: 세션에 secure-{token} 마커가 기록되어 문서를 연 브라우저 세션만 페이지를 요청할 수 있습니다.
  4. The token is returned. 이후 모든 작업에 사용되는 단일 인증 정보입니다.

별도의 워밍업 단계는 없습니다. 이전 라이브러리는 이를 위해 InitCache()을 제공했지만, 이제는 존재하지 않으며 대체되는 것도 없습니다.

세 가지 오버로드는 입력 방식만 다릅니다: 파일 경로, 파일 경로와 포맷별 설정(PdfConfig, WordConfig, …) 중 하나, 혹은 확장자를 기반으로 포맷을 감지하는 Stream와 FileInfo.

위젯이 페이지를 가져오는 방식

클라이언트 위젯은 쿼리 문자열에 토큰을 포함하여 Doconut 미들웨어를 호출합니다. 미들웨어가 수행하는 작업은 요청에 따라 달라집니다:

QueryPurpose
?token=…&page=N렌더링된 페이지 이미지 (PNG)
?token=…&page=N&thumb=1썸네일
?token=…&zoom=…확대된 페이지 렌더링
?token=…&search=term전체 텍스트 검색 (라이선스 제한)
?token=…&bookmarks문서 개요/북마크
?token=…&copy / &showlinks / &fileFormat텍스트 복사, 하이퍼링크 및 포맷 정보
?token=…&metaDICOM 기술 메타데이터; 이 패키지의 DICOM 세션에 대해 501을 반환합니다
?token=…&action=rotate/flip/close페이지 액션 및 명시적 닫기
?token=…&AnnSave=… / &AnnLoad주석 저장/불러오기

이 경로들 각각은 먼저 검증됩니다:

  • No token → 토큰이 없으면 미들웨어가 404를 반환합니다(또는 ShowDoconutInfo = true일 때 버전 배너를 반환).
  • Unknown or expired token → Document session not found. Please re-open document.이 포함된 오류 이미지가 반환됩니다.
  • Session middleware missing (UnsafeMode = false와 함께) → Session middleware not configured. Call UseSession() before UseDoconut().가 포함된 HTTP 500 오류가 반환됩니다.
  • Token opened by a different browser session → You Are Not Authorized To View This Page.이 포함된 오류 이미지가 반환됩니다.

미들웨어가 마운트되는 위치

UseDoconut()은 토큰을 포함한 요청에 응답하며, 마운트 위치와 관계없이 동작합니다. 레퍼런스 애플리케이션은 역사적인 DocImage.axd 요청 형태를 MapWhen 브랜치에 유지하므로 기존 클라이언트는 항상 동일한 URL을 호출합니다. 선택하는 방식에 관계없이 클라이언트의 BasePath이 이에 일치해야 합니다 — ViewerConfig를 참고하세요.

페이지를 열기 노드가 아닌 공유 스토리지에서 제공하는 것은 완전히 다른 구성입니다; Distributed Deployments를 참고하세요.

문서 닫기

csharp
viewer.CloseDocument(token);

CloseDocument은 캐시에서 세션을 제거합니다(이때 기본 문서 엔진이 해제되고 메모리가 즉시 해제됨), secure-{token} 마커를 삭제하고 접근 권한을 취소합니다. 호출은 선택 사항이며 — 슬라이딩 만료가 자동으로 동일한 정리를 수행합니다 — 하지만 대용량 문서의 경우 사용자가 작업을 마치는 즉시 메모리를 해제하는 정중한 방법입니다.

이 메서드는 주입된 Viewer에서 호출됩니다. 이전 패턴—토큰을 닫기 위해 using 블록에서 단명하는 Viewer을 생성하는 방식—은 이제 대응되는 것이 없으며 필요하지 않습니다.

핵심 정리

  • 하나의 열린 문서는 하나의 세션이며 하나의 토큰과 같습니다. 토큰은 브라우저 세션당 존재하며 전역 URL이 아닙니다.
  • 토큰은 슬라이딩 윈도우에서 만료됩니다; DocOptions.TimeOut 이후에 유휴 상태인 뷰어는 다시 열어야 합니다.
  • Viewer은 주입하여 자유롭게 공유할 수 있으며, 세션이 모든 상태를 보유합니다.

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