
무료 ASP.NET MVC 파일 관리자와 내장 PDF 뷰어
무료 ASP.NET MVC 파일 관리자 만들기 (PDF 표시)
서버에 저장된 파일 목록을 보여주고, 사용자가 파일을 다운로드하거나 삭제할 수 있으며, PDF 파일을 사이트를 떠나지 않고 브라우저 내에서 바로 열 수 있는 페이지가 필요하신가요? 이 가이드는 순수 ASP.NET MVC, 내장 세션 캐시, 그리고 Doconut의 범용 문서 뷰어만을 사용해 정확히 그 기능을 구현하는 방법을 보여줍니다.
1. 최소 MVC 애플리케이션 스캐폴드
Visual Studio(무료 Community 에디션 포함)에서 새 MVC 프로젝트를 생성합니다.
파일‑관리자 동작을 호스팅할 FileController를 추가합니다:
public class FileController : Controller
{
private readonly string _root = Path.Combine(Directory.GetCurrentDirectory(), "App_Data", "Docs");
public IActionResult Index()
{
var files = Directory.GetFiles(_root).Select(Path.GetFileName).ToList();
return View(files);
}
public IActionResult Download(string name)
{
var path = Path.Combine(_root, name);
if (!System.IO.File.Exists(path)) return NotFound();
var mime = "application/octet-stream";
return PhysicalFile(path, mime, name);
}
public IActionResult Delete(string name)
{
var path = Path.Combine(_root, name);
if (System.IO.File.Exists(path)) System.IO.File.Delete(path);
return RedirectToAction(nameof(Index));
}
public async Task<IActionResult> ViewPdf(string name)
{
var path = Path.Combine(_root, name);
if (!System.IO.File.Exists(path)) return NotFound();
// 뷰어 토큰은 여기서 생성됩니다 (섹션 2 참조)
var token = await _viewer.OpenDocumentAsync(
path,
new Doconut.PdfConfig { AllowSearch = true },
new DocOptions(),
CancellationToken.None);
ViewBag.Token = token;
ViewBag.BasePath = "doconut"; // 미들웨어 브랜치와 일치합니다
ViewBag.ResPath = "doconut-res/images";// 임베디드 리소스
return View();
}
private readonly Doconut.Viewer _viewer;
public FileController(Doconut.Viewer viewer) => _viewer = viewer;
}
컨트롤러는 세 가지 작업을 수행합니다:
- Index –
App_Data/Docs폴더를 읽고 파일 이름을 뷰에 전달합니다. - Download / Delete – 내장
PhysicalFile헬퍼를 사용하는 표준 MVC 액션입니다. - ViewPdf – 선택한 PDF를 Doconut으로 열고, 보안 토큰을 받아 Razor 뷰에 전달합니다.
2. 세션 상태와 Doconut 서비스 연결
Doconut의 뷰어는 문서를 식별하는 토큰을 보호하기 위해 ASP.NET 세션 상태에 의존합니다. Program.cs(또는 .NET 6 프로젝트의 경우 Startup.cs)에 필요한 서비스를 추가합니다:
var builder = WebApplication.CreateBuilder(args);
// MVC 서비스
builder.Services.AddControllersWithViews();
// 세션 캐시 – 토큰 검증에 필요합니다
builder.Services.AddDistributedMemoryCache();
builder.Services.AddSession();
// Doconut 등록 – 라이선스 파일을 지정합니다
builder.Services.AddDoconut(options =>
{
options.LicensePath = Path.Combine(AppContext.BaseDirectory, "wwwroot", "Doconut.Viewer.lic");
options.MiddlewarePath = "/doconut";
options.ResourcesPath = "/doconut-res";
options.UnsafeMode = false; // 기본 보안을 유지합니다
});
var app = builder.Build();
// 세션은 뷰어 미들웨어보다 먼저 실행되어야 합니다
app.UseSession();
// Doconut 미들웨어는 위에서 구성한 경로에 매핑되어야 합니다.
// 정확한 매핑 호출에 대해서는 Doconut 문서를 참조하세요 (예: app.Map("/doconut", …)).
app.UseRouting();
app.UseEndpoints(endpoints => endpoints.MapDefaultControllerRoute());
app.Run();
핵심 포인트:
AddDistributedMemoryCache는AddSession가 필요로 하는 인‑메모리 스토어를 제공합니다.UseSession()는 Doconut 미들웨어보다 먼저 나타나야 합니다; 그렇지 않으면 런타임 오류 *“Session middleware not configured.”*가 표시됩니다.MiddlewarePath와ResourcesPath은 조정 문자열이며, 실제 미들웨어 경로는 구성한 경로와 일치해야 합니다.
3. 파일‑관리자 뷰 만들기
Views/File/Index.cshtml을 생성합니다. 파일을 나열하고 다운로드, 삭제, PDF 보기를 위한 작업을 제공합니다.
@model List<string>
<h2>Document Library</h2>
<table>
<thead><tr><th>Name</th><th>Actions</th></tr></thead>
<tbody>
@foreach (var f in Model)
{
<tr>
<td>@f</td>
<td>
<a asp-action="Download" asp-route-name="@f">Download</a> |
<a asp-action="Delete" asp-route-name="@f">Delete</a> |
@if (Path.GetExtension(f).Equals(".pdf", StringComparison.OrdinalIgnoreCase))
{
<a asp-action="ViewPdf" asp-route-name="@f">View PDF</a>
}
</td>
</tr>
}
</tbody>
</table>
사용자가 PDF 보기를 클릭하면, ViewPdf 작업이 토큰을 생성하고 뷰어 위젯을 호스팅하는 두 번째 뷰를 반환합니다.
4. Doconut 뷰어 렌더링
Views/File/ViewPdf.cshtml을 생성합니다. 페이지에는 컨테이너 요소만 필요하며, JavaScript 위젯은 포함된 리소스에서 로드됩니다.
@{
var token = ViewBag.Token as string;
var basePath = ViewBag.BasePath as string;
var resPath = ViewBag.ResPath as string;
}
<h2>PDF Preview</h2>
<div id="div_ctlDoc"></div>
<script src="@($"{basePath}/docViewer.js")"></script>
<link rel="stylesheet" href="@($"{basePath}/docViewer.css")" />
<script>
$('#div_ctlDoc').docViewer({
AccessToken: '@token',
BasePath: '@basePath',
ResPath: '@resPath',
FitType: 'width',
showThumbs: true,
autoLoad: true,
onError: function (msg) { console.error(msg); }
});
</script>
위젯은 제공한 AccessToken을 읽고, /doconut/DocImage.axd 엔드포인트에 연결한 뒤 각 페이지를 이미지로 스트리밍합니다. 토큰이 현재 ASP.NET 세션에 연결되어 있기 때문에 사용자는 URL을 복사해 동일한 세션 쿠키 없이 다른 브라우저에서 문서를 볼 수 없습니다.
5. 토큰 만료 및 보안 처리
Doconut의 기본 토큰 시간 제한은 60 분이며 (DocOptions.TimeOut을 통해 구성 가능)입니다. 뷰어가 “Document session not found” 또는 “You Are Not Authorized To View This Page” 메시지를 받으면 세션이 만료되었거나 요청이 다른 브라우저 컨텍스트에서 온 것입니다.
일반적인 해결 방법:
- 페이지 새로 고침 – 컨트롤러가 새로운 토큰을 생성합니다.
- 시간 제한 연장 – 문서를 열 때 사용자 지정
DocOptions을 전달합니다:
var options = new DocOptions { TimeOut = TimeSpan.FromHours(2) };
var token = await _viewer.OpenDocumentAsync(
path,
new Doconut.PdfConfig { AllowSearch = true },
options,
CancellationToken.None);
- 교차 출처 설정 – 세션 쿠키의
SameSite속성이 프런트‑엔드 도메인과 호환되는지 확인합니다. 기본Lax은 대부분의 동일 출처 포털에서 작동합니다.
6. 관리자 확장 (옵션)
핵심 파일 관리자는 이미 기능하지만 다음과 같은 확장을 원할 수 있습니다:
- 업로드 –
IFormFile을 게시하고_root에 저장하는 간단한 폼. - 폴더 탐색 – 상대 경로를 받아들이고 디렉터리 트래버설을 방지하도록
Index작업을 수정합니다 (Path.GetFullPath+StartsWith(_root)검사). - 검색 – 이름으로
files을 필터링한 뒤 뷰에 전달합니다.
이 모든 확장은 동일한 MVC 패턴 내에 머무르며 동일한 세션 보호된 Doconut 뷰어의 이점을 계속 누릴 수 있습니다.
7. 달성한 내용
- 무료 ASP.NET MVC 파일 관리자 – 서드파티 UI 라이브러리 없이, 라이선스 비용도 없습니다.
- 브라우저 내 PDF 렌더링을 Doconut의 범용 뷰어를 통해 제공하여 클라이언트에 Office나 Adobe 설치가 필요하지 않습니다.
- 보안 토큰 기반 접근은 ASP.NET 세션 상태를 활용해 임의 URL 공유를 방지합니다.
- 단일 코드 베이스는 .NET 6 및 .NET 8에서 동작하며, 등록 호출(
AddDoconut,UseSession)만 변경하면 Razor Pages나 최소 API로도 포팅할 수 있습니다.
앱을 IIS, Azure App Service 또는 Docker에 배포하세요 – 동일한 Program.cs 구성으로 어디서든 동작합니다. Doconut은 .NET 6+에서 실행되며 네이티브 Office 구성 요소가 전혀 필요하지 않습니다.