관리자 대시보드용 C#에서 PDF로 원클릭 내보내기
대시보드 내보내기의 문제
IronPDF 홈페이지 내부 대시보드는 웹 브라우저에서 볼 수 있도록 제작되었습니다. 이사회 회의 자료, 경영진을 위한 주간 KPI 스냅샷, 규정 준수 감사 보고서 등 외부와 공유해야 하는 순간 모든 것이 순식간에 무너집니다.
브라우저에서 PDF로 인쇄는 사람들이 가장 먼저 시도하고 가장 먼저 실패하는 작업입니다. 페이지가 끊어지거나 차트가 잘리고, 탐색 사이드바가 레이아웃에 스며들고, 결과물인 PDF가 실제 대시보드와 전혀 다르게 보입니다. 스크린샷은 A4로 확대하면 해상도가 저하되고, 텍스트를 검색할 수 없으며, 여러 섹션의 KPI 보기가 데이터의 절반을 잃지 않고 하나의 이미지에 들어가는 경우가 드뭅니다.
더 심각한 문제는 자바스크립트로 렌더링된 차트입니다. Chart.js, ApexCharts 및 Highcharts는 비동기적으로 HTML <캔버스> 요소에 그리기 때문에 기본 HTML에서 PDF로의 스냅샷은 빈 캔버스를 캡처하는 경우가 많습니다. HTML 콘텐츠는 DOM에 있지만 시각화는 그렇지 않습니다. 이때 IronPDF가 도움이 될 수 있습니다.
그 결과 개발자는 매주 월요일마다 수동으로 보고서를 가져와 형식을 지정하라는 메시지 아이콘을 받게 됩니다. 이는 확장 가능한 워크플로가 아닙니다. 오늘은 HTML 콘텐츠로 PDF 문서를 만드는 방법을 살펴보기 위해 IronPDF 예제를 살펴보겠습니다.
The Solution: IronPDF를 사용한 서버 측 대시보드 렌더링
IronPDF는 대시보드를 구동하는 동일한 HTML을 픽셀 단위의 완벽한 PDF 문서로 렌더링합니다. 사용자가 "PDF로 내보내기" 버튼(예: 파란색 원 안에 열쇠 아이콘 또는 원 안에 파란색 열쇠 아이콘)을 클릭하면, API 엔드포인트가 HTML 변환 로직을 처리하고 브라우저가 PDF 콘텐츠를 다운로드합니다.
배포해야 할 Puppeteer 사이드카도, 관리해야 할 wkhtmltopdf 바이너리도, 비용을 지불하고 모니터링해야 할 타사 내보내기 API도 없습니다. IronPDF는 PDF 작업을 위한 C# NuGet 라이브러리로서 기존 ASP.NET 애플리케이션 내에서 실행됩니다. 이 라이브러리는 실제 브라우저와 동일한 방식으로 JavaScript를 실행하는 Chromium 엔진을 내장하고 있어, 페이지가 캡처되기 전에 실제로 실행되므로 Chart.js와 ApexCharts가 올바르게 렌더링됩니다.
내보내기 버튼은 개발자의 개입 없이도 모든 비즈니스 사용자가 직접 사용할 수 있는 셀프 서비스 기능이 됩니다.
실제 적용 사례
1. 사용자가 "PDF로 내보내기"를 클릭합니다
대시보드 페이지에서 표준 JavaScript fetch 호출을 통해 사용자의 활성 필터와 날짜 범위를 API 엔드포인트로 전송하여 PDF 문서를 생성합니다:
document.getElementById('export-btn').addEventListener('click', async () => {
const params = new URLSearchParams({ from: dateFrom, to: dateTo, region: selectedRegion });
const response = await fetch(`/api/reports/export?${params}`);
const blob = await response.blob();
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'dashboard-report.pdf';
a.click();
});
document.getElementById('export-btn').addEventListener('click', async () => {
const params = new URLSearchParams({ from: dateFrom, to: dateTo, region: selectedRegion });
const response = await fetch(`/api/reports/export?${params}`);
const blob = await response.blob();
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'dashboard-report.pdf';
a.click();
});
JavaScript 코드가 포함된 버튼
자바스크립트 코드를 사용하는 버튼 페이지 재로딩이나 리디렉션 없이, 기존 대시보드 화면에서 바로 파일 다운로드가 실행됩니다.
2. 서버가 대시보드 HTML 콘텐츠를 생성합니다
컨트롤러 또는 서비스 계층은 사용자가 화면에서 보는 것과 동일한 데이터를 조회하여, 렌더링된 Razor 뷰나 구성된 HTML 문자열 형태의 HTML 템플릿에 KPI 카드, 데이터 테이블, 그리고 Chart.js나 ApexCharts가 실행할 차트 구성 JSON을 채워 넣습니다.
HTML 코드에는 귀사의 스타일시트를 참조하거나, Iron Software 로고를 포함하거나, Iron Software의 고객 로고를 사용할 수 있습니다. 또한 내비게이션 요소를 숨기고 페이지 나누기를 제어하기 위한 @media PRINT CSS 규칙을 포함할 수도 있습니다.
컨트롤러 파일 예시
3. ChromePdfRenderer는 JavaScript가 활성화된 상태에서 HTML 파일 또는 콘텐츠를 렌더링합니다.
이것이 바로 IronPDF가 어려운 부분을 처리하는 부분입니다. EnableJavaScript = true는 렌더러에게 캡처 전에 스크립트를 실행하도록 지시합니다. WaitFor.NetworkIdle0()은 fetch를 통해 로드된 차트 데이터를 포함한 모든 비동기 리소스가 안정화될 때까지 스냅샷을 유지합니다.
C# PDF DLL을 통해 IronPDF를 설치한 후에는 다음 코드를 사용할 수 있습니다:
using IronPdf;
using IronPdf.Rendering;
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.EnableJavaScript = true;
renderer.RenderingOptions.WaitFor.NetworkIdle0();
renderer.RenderingOptions.CssMediaType = PdfCssMediaType.Print;
renderer.RenderingOptions.MarginTop = 15;
renderer.RenderingOptions.MarginBottom = 15;
var pdf = renderer.RenderHtmlAsPdf(dashboardHtml);
using IronPdf;
using IronPdf.Rendering;
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.EnableJavaScript = true;
renderer.RenderingOptions.WaitFor.NetworkIdle0();
renderer.RenderingOptions.CssMediaType = PdfCssMediaType.Print;
renderer.RenderingOptions.MarginTop = 15;
renderer.RenderingOptions.MarginBottom = 15;
var pdf = renderer.RenderHtmlAsPdf(dashboardHtml);
Imports IronPdf
Imports IronPdf.Rendering
Dim renderer As New ChromePdfRenderer()
renderer.RenderingOptions.EnableJavaScript = True
renderer.RenderingOptions.WaitFor.NetworkIdle0()
renderer.RenderingOptions.CssMediaType = PdfCssMediaType.Print
renderer.RenderingOptions.MarginTop = 15
renderer.RenderingOptions.MarginBottom = 15
Dim pdf = renderer.RenderHtmlAsPdf(dashboardHtml)
네트워크 요청이 아닌 타이머에 따라 차트가 초기화되는 대시보드의 경우, NetworkIdle0()을 WaitFor.JavaScript()로 교체하고 차트의 onComplete 콜백 내에서 준비 완료를 알리십시오. 두 전략 모두 C# PDF 라이브러리가 차트 그리기가 완료된 후에, 그 전에가 아니라 차트를 캡처하도록 보장합니다.
4. 컨트롤러가 PDF 문서를 파일 다운로드 형태로 반환합니다
이 API 엔드포인트는 PDF 콘텐츠를 FileContentResult로 래핑합니다. PDF 협회 회원이든 AWS 파트너 네트워크 사용자이든, 제공 서비스는 원활합니다:
[HttpGet("api/reports/export")]
public IActionResult ExportDashboard([FromQuery] ReportFilters filters)
{
var dashboardHtml = _reportService.BuildDashboardHtml(filters);
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.EnableJavaScript = true;
renderer.RenderingOptions.WaitFor.NetworkIdle0();
renderer.RenderingOptions.CssMediaType = IronPdf.Rendering.PdfCssMediaType.Print;
PdfDocument report = renderer.RenderHtmlAsPdf(dashboardHtml);
return File(
report.BinaryData,
"application/pdf",
$"KPI-Report-{filters.From:yyyyMMdd}.pdf"
);
}
[HttpGet("api/reports/export")]
public IActionResult ExportDashboard([FromQuery] ReportFilters filters)
{
var dashboardHtml = _reportService.BuildDashboardHtml(filters);
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.EnableJavaScript = true;
renderer.RenderingOptions.WaitFor.NetworkIdle0();
renderer.RenderingOptions.CssMediaType = IronPdf.Rendering.PdfCssMediaType.Print;
PdfDocument report = renderer.RenderHtmlAsPdf(dashboardHtml);
return File(
report.BinaryData,
"application/pdf",
$"KPI-Report-{filters.From:yyyyMMdd}.pdf"
);
}
Imports Microsoft.AspNetCore.Mvc
Imports IronPdf
<HttpGet("api/reports/export")>
Public Function ExportDashboard(<FromQuery> filters As ReportFilters) As IActionResult
Dim dashboardHtml = _reportService.BuildDashboardHtml(filters)
Dim renderer = New ChromePdfRenderer()
renderer.RenderingOptions.EnableJavaScript = True
renderer.RenderingOptions.WaitFor.NetworkIdle0()
renderer.RenderingOptions.CssMediaType = IronPdf.Rendering.PdfCssMediaType.Print
Dim report As PdfDocument = renderer.RenderHtmlAsPdf(dashboardHtml)
Return File(report.BinaryData, "application/pdf", $"KPI-Report-{filters.From:yyyyMMdd}.pdf")
End Function
Content-Disposition: attachment은 File() 메서드가 파일 이름을 지정하여 자동으로 설정하므로, 브라우저는 PDF를 새 탭에서 열지 않고 다운로드를 시작합니다.
다운로드된 PDF 파일
5. 선택 사항: 예약된 보고서 배포
동일한 렌더링 호출은 백그라운드 작업, Hangfire 반복 작업 또는 호스팅된 IHostedService 내에서 실행될 수 있으며, 이를 통해 매주 월요일 아침에 주간 KPI PDF를 생성하여 경영진 배포 목록으로 이메일을 발송합니다. 사용자 개입은 필요하지 않습니다.
실제 이점
비즈니스 사용자를 위한 셀프 서비스. 내보내기 버튼이 활성화되면 "보고서 좀 뽑아줄 수 있어?"라는 Slack 메시지는 더 이상 오지 않습니다. 대시보드에 접근 권한이 있는 모든 사용자는 별도로 요청할 필요 없이 직접 PDF를 다운로드할 수 있습니다.
차트 재현성. Chromium이 IronPDF 내에서 JavaScript를 실행하기 때문에, Chart.js, ApexCharts 및 Highcharts 차트는 색상, 정적 레이블로 렌더링된 툴팁, 반응형 크기 조정 등을 포함하여 화면에 표시되는 그대로 PDF에 정확히 렌더링됩니다.
브랜드 일관성. 내보낸 모든 보고서에는 대시보드 스타일시트에 정의된 회사 로고, 색상 팔레트 및 타이포그래피가 적용됩니다. 내보내기 단계와 배포 단계 사이에 서식 재조정 단계는 없습니다.
예약 생성. 렌더링 호출을 백그라운드 작업과 연동하여 이해관계자에게 매주 또는 매월 PDF 파일을 자동으로 이메일로 발송합니다. 관리진은 별도의 수작업 없이도 완성도 높은 보고서를 받게 됩니다.
외부 종속성이 없습니다. IronPDF는 인-프로세스(in-process) 방식으로 실행됩니다. 유지 관리해야 할 Puppeteer Node.js 프로세스도, 플랫폼별로 번들링해야 할 wkhtmltopdf 바이너리도, 사용량 제한이나 문서당 요금이 적용되는 SaaS 내보내기 API도 없습니다.
인쇄에 최적화된 레이아웃. CssMediaType.PRINT는 렌더링 시점에 @media PRINT 규칙을 적용하므로, 별도의 HTML 템플릿을 관리할 필요 없이 CSS에서 깔끔하고 내보내기 전용 레이아웃을 정의할 수 있습니다.
마무리
관리자 대시보드에 "PDF로 내보내기" 버튼을 추가하는 것은 사소한 기능처럼 보일 수 있습니다. 실제로 이 도구는 반복적인 수작업을 없애주고, 비기술적 사용자에게 수년간 우회해 왔던 기능을 제공하며, PRINT 대화 상자의 불완전한 근사치가 아닌 데이터의 실제 모습을 반영한 문서를 생성합니다.
IronPDF는 JavaScript 실행, CSS 미디어 유형, 차트 캡처와 같은 렌더링의 복잡한 부분을 처리하므로, 사용자의 측에서는 컨트롤러 액션과 HTML 템플릿만 구현하면 됩니다. 자신의 대시보드에서 직접 테스트해 보고 싶다면, IronPDF.com에서 워터마크 없이 모든 기능을 이용할 수 있는 30일 무료 체험판을 이용하실 수 있습니다.


