Rotativa에서 IronPDF로의 마이그레이션 방법 (C#)
Rotativa에서 IronPDF로 마이그레이션하면 중요한 보안 취약점을 해결하면서 PDF 생성 워크플로우를 현대화합니다. 이 가이드는 포기된 wkhtmltopdf 의존성을 제거하고, 최신 CSS 및 JavaScript 지원을 가능하게 하며 ASP.NET MVC를 넘어 크로스 플랫폼 호환성을 제공하는 완전한 단계별 마이그레이션 경로를 제공합니다.
왜 Rotativa에서 IronPDF로 마이그레이션해야 하는가
Rotativa이해하기
Rotativa는 C#에서 PDF 생성을 위해 개발자들 사이에서 오랫동안 인기 있는 선택이었습니다. HTML 내용을 PDF 형식으로 변환하기 위해 wkhtmltopdf 도구를 활용합니다. Rotativa는 ASP.NET MVC 애플리케이션을 위해 특별히 설계된 오픈 소스 라이브러리입니다. 그러나 상당한 사용자를 끌어들이는 동안, Rotativa가 구식 기술 스택에 의존하고 있다는 점은 모든 개발자에게 즉각적으로 명확하지 않을 수 있는 문제가 됩니다.
근본적으로 Rotativa는 PDF 생성을 ASP.NET MVC 프로젝트에 통합하는 간단한 방법을 제공하며, 이를 위한 백엔드 기능에는 wkhtmltopdf를 이용합니다.
중대한 보안 권고
Rotativa는 해결되지 않은 중대한 보안 취약점을 가진 wkhtmltopdf를 포함합니다.
| 속성 | 값 |
|---|---|
| CVE ID | CVE-2022-35583 |
| 심각도 | 심각한 (9.8/10) |
| 공격 벡터 | 네트워크 |
| 상태 | 절대 패치되지 않음 |
| 영향을 받음 | 모든Rotativa버전 |
wkhtmltopdf는 2022년 12월에 공식적으로 포기되었습니다. 유지 관리자들은 보안 취약점을 수정하지 않을 것이라고 명시적으로 밝혔습니다. Rotativa를 사용하는 모든 애플리케이션은 영구적으로 노출됩니다.
공격 작동 방식
<iframe src="http://169.254.169.254/latest/meta-data/iam/security-credentials/"></iframe>
<img src="http://internal-database:5432/admin" />
<iframe src="http://169.254.169.254/latest/meta-data/iam/security-credentials/"></iframe>
<img src="http://internal-database:5432/admin" />
영향:
- AWS/Azure/GCP 클라우드 메타데이터 엔드포인트에 접근
- 내부 API 데이터 및 자격증명 탈취
- 내부 네트워크 포트 스캔
- 민감한 구성 정보 유출
기술 위기
Rotativa는 wkhtmltopdf를 감싸고 있으며, 이를 사용하는 기술들:
- Qt WebKit 4.8 (2012년)
- Flexbox 지원 없음
- CSS Grid 지원 없음
- JavaScript 실행 오류
- ES6+ 지원 없음
Rotativa와IronPDF비교
| 기능 | Rotativa | IronPDF |
|---|---|---|
| 프로젝트 호환성 | ASP.NET MVC 전용 | 모든 .NET 프로젝트 유형 (MVC, Razor Pages, Blazor 등) |
| 유지보수 | 버려짐 | 활발히 유지 관리됨 |
| 보안 | wkhtmltopdf 종속성으로 인한 취약성 (CVE-2022-35583) | 정기적인 업데이트 및 보안 패치 |
| HTML 렌더링 | 구식 WebKit | 최신 크로뮴 |
| CSS3 | 부분적 | 지원됨 |
| 플렉스박스/그리드 | 지원되지 않음 | 지원됨 |
| JavaScript | 신뢰할 수 없음 | 전체 ES6+ |
| Razor Pages | 지원되지 않음 | 지원됨 |
| Blazor | 지원되지 않음 | 지원됨 |
| PDF 조작 | 사용 불가 | 전체 |
| 디지털 서명 | 사용 불가 | 전체 |
| PDF/A 준수 | 사용 불가 | 전체 |
| Async/Await | 동기식만 | 완전 비동기 |
| 오픈 소스 | 예, MIT 라이선스 | 아니요, 상업용 라이선스 |
.NET 10 및 C# 14 채택을 계획 중인 팀을 위해 IronPDF는 Rotativa가 제공할 수 없는 현대적 Chrome 렌더링 및 플랫폼 간 지원을 제공합니다.
시작하기 전에
필수 조건
- .NET 환경: .NET Framework 4.6.2+ 또는 .NET Core 3.1+ / .NET 5/6/7/8/9+
- NuGet 접근 권한: NuGet 패키지를 설치할 수 있는 능력
- IronPDF 라이선스: ironpdf.com에서 라이선스 키를 획득하세요
NuGet 패키지 변경 사항
# Remove Rotativa
dotnet remove package Rotativa
dotnet remove package Rotativa.AspNetCore
# Install IronPDF
dotnet add package IronPdf
# Remove Rotativa
dotnet remove package Rotativa
dotnet remove package Rotativa.AspNetCore
# Install IronPDF
dotnet add package IronPdf
wkhtmltopdf 바이너리 제거
프로젝트에서 다음 파일을 삭제하세요:
wkhtmltopdf.exewkhtmltox.dll- 모든
Rotativa/폴더
이 파일들이 CVE-2022-35583의 원인입니다. IronPDF는 네이티브 바이너리가 필요하지 않습니다.
라이선스 구성
// Add in Program.cs or Startup.cs
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
// Add in Program.cs or Startup.cs
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
' Add in Program.vb or Startup.vb
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY"
완전한 API 참조
네임스페이스 변경
// Before: Rotativa
using Rotativa;
using Rotativa.Options;
using Rotativa.AspNetCore;
// After: IronPDF
using IronPdf;
using IronPdf.Rendering;
// Before: Rotativa
using Rotativa;
using Rotativa.Options;
using Rotativa.AspNetCore;
// After: IronPDF
using IronPdf;
using IronPdf.Rendering;
' Before: Rotativa
Imports Rotativa
Imports Rotativa.Options
Imports Rotativa.AspNetCore
' After: IronPDF
Imports IronPdf
Imports IronPdf.Rendering
핵심 클래스 매핑
| Rotativa클래스 | IronPDF 동등 |
|---|---|
ViewAsPdf |
ChromePdfRenderer |
ActionAsPdf |
ChromePdfRenderer.RenderUrlAsPdf() |
UrlAsPdf |
ChromePdfRenderer.RenderUrlAsPdf() |
Orientation 열거형 |
PdfPaperOrientation 열거형 |
Size 열거형 |
PdfPaperSize 열거형 |
페이지 자리 표시자 변환
| Rotativa플레이스홀더 | IronPDF 플레이스홀더 |
|---|---|
[page] |
{page} |
[topage] |
{total-pages} |
[date] |
{date} |
[time] |
{time} |
[title] |
{html-title} |
[sitepage] |
{url} |
코드 마이그레이션 예제
예제 1: HTML에서 PDF로 변환
이전 (Rotativa):
// NuGet: Install-Package Rotativa.Core
using Microsoft.AspNetCore.Mvc;
using Rotativa.AspNetCore;
using System.Threading.Tasks;
namespace RotativaExample
{
public class PdfController : Controller
{
public async Task<IActionResult> GeneratePdf()
{
var htmlContent = "<h1>Hello World</h1><p>This is a PDF document.</p>";
//Rotativarequires returning a ViewAsPdf result from MVC controller
return new ViewAsPdf()
{
ViewName = "PdfView",
PageSize = Rotativa.AspNetCore.Options.Size.A4
};
}
}
}
// NuGet: Install-Package Rotativa.Core
using Microsoft.AspNetCore.Mvc;
using Rotativa.AspNetCore;
using System.Threading.Tasks;
namespace RotativaExample
{
public class PdfController : Controller
{
public async Task<IActionResult> GeneratePdf()
{
var htmlContent = "<h1>Hello World</h1><p>This is a PDF document.</p>";
//Rotativarequires returning a ViewAsPdf result from MVC controller
return new ViewAsPdf()
{
ViewName = "PdfView",
PageSize = Rotativa.AspNetCore.Options.Size.A4
};
}
}
}
Imports Microsoft.AspNetCore.Mvc
Imports Rotativa.AspNetCore
Imports System.Threading.Tasks
Namespace RotativaExample
Public Class PdfController
Inherits Controller
Public Async Function GeneratePdf() As Task(Of IActionResult)
Dim htmlContent As String = "<h1>Hello World</h1><p>This is a PDF document.</p>"
' Rotativa requires returning a ViewAsPdf result from MVC controller
Return New ViewAsPdf() With {
.ViewName = "PdfView",
.PageSize = Rotativa.AspNetCore.Options.Size.A4
}
End Function
End Class
End Namespace
이후 (IronPDF):
// NuGet: Install-Package IronPdf
using IronPdf;
using System;
namespace IronPdfExample
{
class Program
{
static void Main(string[] args)
{
var renderer = new ChromePdfRenderer();
var htmlContent = "<h1>Hello World</h1><p>This is a PDF document.</p>";
var pdf = renderer.RenderHtmlAsPdf(htmlContent);
pdf.SaveAs("output.pdf");
Console.WriteLine("PDF generated successfully!");
}
}
}
// NuGet: Install-Package IronPdf
using IronPdf;
using System;
namespace IronPdfExample
{
class Program
{
static void Main(string[] args)
{
var renderer = new ChromePdfRenderer();
var htmlContent = "<h1>Hello World</h1><p>This is a PDF document.</p>";
var pdf = renderer.RenderHtmlAsPdf(htmlContent);
pdf.SaveAs("output.pdf");
Console.WriteLine("PDF generated successfully!");
}
}
}
Imports IronPdf
Imports System
Namespace IronPdfExample
Class Program
Shared Sub Main(ByVal args As String())
Dim renderer = New ChromePdfRenderer()
Dim htmlContent = "<h1>Hello World</h1><p>This is a PDF document.</p>"
Dim pdf = renderer.RenderHtmlAsPdf(htmlContent)
pdf.SaveAs("output.pdf")
Console.WriteLine("PDF generated successfully!")
End Sub
End Class
End Namespace
이 예제는 근본적인 아키텍처 차이를 보여줍니다. Rotativa는 MVC 컨트롤러 액션에서 ViewAsPdf 결과를 반환하여 ASP.NET MVC 프레임워크와 연결됩니다. 이 패턴은 MVC 요청 파이프라인 내에서만 작동하며 Razor 뷰를 렌더링하기 위해 필요합니다.
IronPDF는 콘솔 애플리케이션, 웹 API, Blazor, Razor Pages 또는 모든 .NET 프로젝트 유형에서 작동합니다. HTML 문자열을 사용하여 RenderHtmlAsPdf()을 호출하고 결과를 저장합니다. MVC 컨트롤러가 필요 없으며, 뷰 종속성이 없습니다. HTML에서 PDF로의 문서에서 포괄적인 예제를 참조하세요.
예제 2: URL에서 PDF로 변환
이전 (Rotativa):
// NuGet: Install-Package Rotativa.Core
using Microsoft.AspNetCore.Mvc;
using Rotativa.AspNetCore;
using System.Threading.Tasks;
namespace RotativaExample
{
public class UrlPdfController : Controller
{
public async Task<IActionResult> ConvertUrlToPdf()
{
//Rotativaworks within MVC framework and returns ActionResult
return new UrlAsPdf("https://www.example.com")
{
FileName = "webpage.pdf",
PageSize = Rotativa.AspNetCore.Options.Size.A4,
PageOrientation = Rotativa.AspNetCore.Options.Orientation.Portrait
};
}
}
}
// NuGet: Install-Package Rotativa.Core
using Microsoft.AspNetCore.Mvc;
using Rotativa.AspNetCore;
using System.Threading.Tasks;
namespace RotativaExample
{
public class UrlPdfController : Controller
{
public async Task<IActionResult> ConvertUrlToPdf()
{
//Rotativaworks within MVC framework and returns ActionResult
return new UrlAsPdf("https://www.example.com")
{
FileName = "webpage.pdf",
PageSize = Rotativa.AspNetCore.Options.Size.A4,
PageOrientation = Rotativa.AspNetCore.Options.Orientation.Portrait
};
}
}
}
Imports Microsoft.AspNetCore.Mvc
Imports Rotativa.AspNetCore
Imports System.Threading.Tasks
Namespace RotativaExample
Public Class UrlPdfController
Inherits Controller
Public Async Function ConvertUrlToPdf() As Task(Of IActionResult)
' Rotativa works within MVC framework and returns ActionResult
Return New UrlAsPdf("https://www.example.com") With {
.FileName = "webpage.pdf",
.PageSize = Rotativa.AspNetCore.Options.Size.A4,
.PageOrientation = Rotativa.AspNetCore.Options.Orientation.Portrait
}
End Function
End Class
End Namespace
이후 (IronPDF):
// NuGet: Install-Package IronPdf
using IronPdf;
using System;
namespace IronPdfExample
{
class Program
{
static void Main(string[] args)
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderUrlAsPdf("https://www.example.com");
pdf.SaveAs("webpage.pdf");
Console.WriteLine("URL converted to PDF successfully!");
}
}
}
// NuGet: Install-Package IronPdf
using IronPdf;
using System;
namespace IronPdfExample
{
class Program
{
static void Main(string[] args)
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderUrlAsPdf("https://www.example.com");
pdf.SaveAs("webpage.pdf");
Console.WriteLine("URL converted to PDF successfully!");
}
}
}
Imports IronPdf
Imports System
Namespace IronPdfExample
Class Program
Shared Sub Main(ByVal args As String())
Dim renderer = New ChromePdfRenderer()
Dim pdf = renderer.RenderUrlAsPdf("https://www.example.com")
pdf.SaveAs("webpage.pdf")
Console.WriteLine("URL converted to PDF successfully!")
End Sub
End Class
End Namespace
Rotativa의 UrlAsPdf 클래스는 MVC 컨트롤러에서 ActionResult 반환을 요구합니다. IronPDF의 RenderUrlAsPdf() 메소드는 모든 컨텍스트에서 호출할 수 있으며 PdfDocument 객체를 직접 반환합니다. URL 렌더링은 wkhtmltopdf의 취약하고 구식인 WebKit 엔진 대신 현대적 Chrome을 사용합니다. 자세한 내용은 튜토리얼을 참조하세요.
예제 3: 페이지 번호가 있는 헤더와 푸터
이전 (Rotativa):
// NuGet: Install-Package Rotativa.Core
using Microsoft.AspNetCore.Mvc;
using Rotativa.AspNetCore;
using Rotativa.AspNetCore.Options;
using System.Threading.Tasks;
namespace RotativaExample
{
public class HeaderFooterController : Controller
{
public async Task<IActionResult> GeneratePdfWithHeaderFooter()
{
return new ViewAsPdf("Report")
{
PageSize = Size.A4,
PageMargins = new Margins(20, 10, 20, 10),
CustomSwitches = "--header-center \"Page Header\" --footer-center \"Page [page] of [toPage]\""
};
}
}
}
// NuGet: Install-Package Rotativa.Core
using Microsoft.AspNetCore.Mvc;
using Rotativa.AspNetCore;
using Rotativa.AspNetCore.Options;
using System.Threading.Tasks;
namespace RotativaExample
{
public class HeaderFooterController : Controller
{
public async Task<IActionResult> GeneratePdfWithHeaderFooter()
{
return new ViewAsPdf("Report")
{
PageSize = Size.A4,
PageMargins = new Margins(20, 10, 20, 10),
CustomSwitches = "--header-center \"Page Header\" --footer-center \"Page [page] of [toPage]\""
};
}
}
}
Imports Microsoft.AspNetCore.Mvc
Imports Rotativa.AspNetCore
Imports Rotativa.AspNetCore.Options
Imports System.Threading.Tasks
Namespace RotativaExample
Public Class HeaderFooterController
Inherits Controller
Public Async Function GeneratePdfWithHeaderFooter() As Task(Of IActionResult)
Return New ViewAsPdf("Report") With {
.PageSize = Size.A4,
.PageMargins = New Margins(20, 10, 20, 10),
.CustomSwitches = "--header-center ""Page Header"" --footer-center ""Page [page] of [toPage]"""
}
End Function
End Class
End Namespace
이후 (IronPDF):
// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Rendering;
using System;
namespace IronPdfExample
{
class Program
{
static void Main(string[] args)
{
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.TextHeader = new TextHeaderFooter()
{
CenterText = "Page Header",
DrawDividerLine = true
};
renderer.RenderingOptions.TextFooter = new TextHeaderFooter()
{
CenterText = "Page {page} of {total-pages}",
DrawDividerLine = true
};
var htmlContent = "<h1>Report Title</h1><p>Report content goes here.</p>";
var pdf = renderer.RenderHtmlAsPdf(htmlContent);
pdf.SaveAs("report.pdf");
Console.WriteLine("PDF with headers and footers created successfully!");
}
}
}
// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Rendering;
using System;
namespace IronPdfExample
{
class Program
{
static void Main(string[] args)
{
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.TextHeader = new TextHeaderFooter()
{
CenterText = "Page Header",
DrawDividerLine = true
};
renderer.RenderingOptions.TextFooter = new TextHeaderFooter()
{
CenterText = "Page {page} of {total-pages}",
DrawDividerLine = true
};
var htmlContent = "<h1>Report Title</h1><p>Report content goes here.</p>";
var pdf = renderer.RenderHtmlAsPdf(htmlContent);
pdf.SaveAs("report.pdf");
Console.WriteLine("PDF with headers and footers created successfully!");
}
}
}
Imports IronPdf
Imports IronPdf.Rendering
Imports System
Namespace IronPdfExample
Class Program
Shared Sub Main(ByVal args As String())
Dim renderer = New ChromePdfRenderer()
renderer.RenderingOptions.TextHeader = New TextHeaderFooter() With {
.CenterText = "Page Header",
.DrawDividerLine = True
}
renderer.RenderingOptions.TextFooter = New TextHeaderFooter() With {
.CenterText = "Page {page} of {total-pages}",
.DrawDividerLine = True
}
Dim htmlContent = "<h1>Report Title</h1><p>Report content goes here.</p>"
Dim pdf = renderer.RenderHtmlAsPdf(htmlContent)
pdf.SaveAs("report.pdf")
Console.WriteLine("PDF with headers and footers created successfully!")
End Sub
End Class
End Namespace
Rotativa는 명령줄 인수를 wkhtmltopdf에 전달하기 위해 CustomSwitches를 사용하며, [page] 및 [toPage]와 같은 플레이스홀더를 포함한 헤더 및 푸터 구성을 제공합니다. 이 문자열 기반 접근 방식은 오류 발생 가능성이 높으며 컴파일 시 유효성을 검사하기 어렵습니다.
IronPDF는 CenterText 및 DrawDividerLine와 같은 속성을 가진 강력한 형식의 TextHeaderFooter 객체를 사용합니다. 플레이스홀더 문법이 [page]에서 {page}로, [toPage]에서 {total-pages}로 변경됩니다. 타입이 지정된 속성은 IntelliSense, 컴파일 시 검사, 오타의 위험 없음 등을 제공합니다.
MVC 전용 아키텍처 문제
Rotativa는 ASP.NET MVC 5 및 이전 버전용으로 설계되었습니다:
// ❌Rotativa- Only works with classic MVC pattern
public class InvoiceController : Controller
{
public ActionResult InvoicePdf(int id)
{
var model = GetInvoice(id);
return new ViewAsPdf("Invoice", model); // Tied to MVC Views
}
}
// Problems:
// - No Razor Pages support
// - No Blazor support
// - No minimal APIs support
// - No ASP.NET Core native integration
// ❌Rotativa- Only works with classic MVC pattern
public class InvoiceController : Controller
{
public ActionResult InvoicePdf(int id)
{
var model = GetInvoice(id);
return new ViewAsPdf("Invoice", model); // Tied to MVC Views
}
}
// Problems:
// - No Razor Pages support
// - No Blazor support
// - No minimal APIs support
// - No ASP.NET Core native integration
Imports System.Web.Mvc
Public Class InvoiceController
Inherits Controller
Public Function InvoicePdf(id As Integer) As ActionResult
Dim model = GetInvoice(id)
Return New ViewAsPdf("Invoice", model) ' Tied to MVC Views
End Function
End Class
' Problems:
' - No Razor Pages support
' - No Blazor support
' - No minimal APIs support
' - No ASP.NET Core native integration
IronPDF는 보기 렌더링을 PDF 생성과 분리하여 실제로 더 유연합니다. MVC 뷰뿐만 아니라 모든 HTML을 렌더링할 수 있습니다.
비동기 패턴 마이그레이션
Rotativa는 스레드를 차단합니다; IronPDF는 전체 비동기/await를 지원합니다:
// ❌Rotativa- Blocks the thread
public ActionResult GeneratePdf()
{
return new ViewAsPdf("Report");
// This blocks the request thread until PDF is complete
// Poor scalability under load
}
// ✅IronPDF- 완전 비동기 support
public async Task<IActionResult> GeneratePdf()
{
var renderer = new ChromePdfRenderer();
var pdf = await renderer.RenderHtmlAsPdfAsync(html);
return File(pdf.BinaryData, "application/pdf");
// Non-blocking, better scalability
}
// ❌Rotativa- Blocks the thread
public ActionResult GeneratePdf()
{
return new ViewAsPdf("Report");
// This blocks the request thread until PDF is complete
// Poor scalability under load
}
// ✅IronPDF- 완전 비동기 support
public async Task<IActionResult> GeneratePdf()
{
var renderer = new ChromePdfRenderer();
var pdf = await renderer.RenderHtmlAsPdfAsync(html);
return File(pdf.BinaryData, "application/pdf");
// Non-blocking, better scalability
}
' ❌Rotativa- Blocks the thread
Public Function GeneratePdf() As ActionResult
Return New ViewAsPdf("Report")
' This blocks the request thread until PDF is complete
' Poor scalability under load
End Function
' ✅IronPDF- 완전 비동기 support
Public Async Function GeneratePdf() As Task(Of IActionResult)
Dim renderer As New ChromePdfRenderer()
Dim pdf = Await renderer.RenderHtmlAsPdfAsync(html)
Return File(pdf.BinaryData, "application/pdf")
' Non-blocking, better scalability
End Function
이동 후 새로운 기능
IronPDF로 마이그레이션한 후에는 Rotativa가 제공할 수 없는 기능을 얻게 됩니다:
PDF 병합
var merged = PdfDocument.Merge(pdf1, pdf2, pdf3);
merged.SaveAs("complete.pdf");
var merged = PdfDocument.Merge(pdf1, pdf2, pdf3);
merged.SaveAs("complete.pdf");
Dim merged = PdfDocument.Merge(pdf1, pdf2, pdf3)
merged.SaveAs("complete.pdf")
디지털 서명
var signature = new PdfSignature("certificate.pfx", "password");
pdf.Sign(signature);
var signature = new PdfSignature("certificate.pfx", "password");
pdf.Sign(signature);
Dim signature = New PdfSignature("certificate.pfx", "password")
pdf.Sign(signature)
비밀번호 보호
pdf.SecuritySettings.UserPassword = "secret";
pdf.SecuritySettings.UserPassword = "secret";
pdf.SecuritySettings.UserPassword = "secret"
워터마크
pdf.ApplyWatermark("<h1 style='color:red; opacity:0.3;'>DRAFT</h1>");
pdf.ApplyWatermark("<h1 style='color:red; opacity:0.3;'>DRAFT</h1>");
IRON VB CONVERTER ERROR developers@ironsoftware.com
PDF/A 기록 보관 규정 준수
pdf.SaveAsPdfA("archive.pdf", PdfAVersions.PdfA3b);
pdf.SaveAsPdfA("archive.pdf", PdfAVersions.PdfA3b);
pdf.SaveAsPdfA("archive.pdf", PdfAVersions.PdfA3b)
최신 CSS 지원
// This now works (broke in Rotativa)
var html = @"
<div style='display: flex; justify-content: space-between;'>
<div>Left</div>
<div>Right</div>
</div>
<div style='display: grid; grid-template-columns: 1fr 1fr 1fr;'>
<div>Col 1</div><div>Col 2</div><div>Col 3</div>
</div>";
var pdf = renderer.RenderHtmlAsPdf(html); // Works!
// This now works (broke in Rotativa)
var html = @"
<div style='display: flex; justify-content: space-between;'>
<div>Left</div>
<div>Right</div>
</div>
<div style='display: grid; grid-template-columns: 1fr 1fr 1fr;'>
<div>Col 1</div><div>Col 2</div><div>Col 3</div>
</div>";
var pdf = renderer.RenderHtmlAsPdf(html); // Works!
' This now works (broke in Rotativa)
Dim html As String = "
<div style='display: flex; justify-content: space-between;'>
<div>Left</div>
<div>Right</div>
</div>
<div style='display: grid; grid-template-columns: 1fr 1fr 1fr;'>
<div>Col 1</div><div>Col 2</div><div>Col 3</div>
</div>"
Dim pdf = renderer.RenderHtmlAsPdf(html) ' Works!
마이그레이션 체크리스트
사전 마이그레이션
- 코드베이스에서 모든Rotativa사용을 식별
- RenderingOptions로의 변환에 사용된 CustomSwitches 문서화
- 변환을 위한 헤더/푸터 플레이스홀더 문법 주의 (
[page]→{page}) - ironpdf.com에서IronPDF라이선스 키 획득
패키지 변경 사항
Rotativa및Rotativa.AspNetCoreNuGet 패키지 제거- wkhtmltopdf 바이너리 삭제 (
wkhtmltopdf.exe,wkhtmltox.dll) IronPdfNuGet Install-Package
코드 변경 사항
- 네임스페이스 가져오기 업데이트 (
using Rotativa;→using IronPdf;) ViewAsPdf을ChromePdfRenderer+RenderHtmlAsPdf()로 대체UrlAsPdf을(를)RenderUrlAsPdf()(으)로 대체CustomSwitches을RenderingOptions속성으로 변환- 플레이스홀더 문법 업데이트 (
[page]→{page},[topage]→{total-pages}) - 개별
MarginRight로PageMargins대체 - 적절한 곳에서 비동기 패턴으로 변경
- 애플리케이션 시작 시 라이선스 초기화 추가
마이그레이션 이후
- 모든 PDF 생성이 올바르게 작동하는지 확인
- PDF 출력 품질 비교 (Chromium은 더 정확하게 렌더링합니다)
- CSS 렌더링 개선 사항 확인 (Flexbox/Grid가 이제 작동합니다)
- JavaScript 실행 테스트 (이제 Chromium으로 신뢰할 수 있음)
- 보안 스캔 통과 확인(CVE-2022-35583 플래그 없음)
- wkhtmltopdf 설치 제거를 위해 Docker 구성 업데이트

