Ir para o conteúdo do rodapé
USANDO O IRONPDF

C# Imprimir Formulário para PDF -- Guia Completo do Desenvolvedor

O Problema Com Templates PDF Paralelos

Página inicial do IronPDF As views Razor já estão construídas. A página de detalhes da fatura renderiza itens de linha, calcula totais e aplica o estilo da folha de estilo da empresa. A página de status do projeto mostra a divisão de tarefas com seções condicionais que só aparecem quando os marcos estão atrasados. A visualização do contracheque formata ganhos, deduções e valores YTD em uma tabela que a equipe de RH levou duas semanas para acertar. Todo esse trabalho está feito, e então um responsável solicita um botão "Download como PDF".

A resposta padrão é construir um segundo template: uma string HTML ou definição de relatório que reproduz o mesmo layout para o caminho do PDF. Esse segundo template começa como uma cópia do primeiro, então imediatamente começa a divergir. O designer de UI atualiza o estilo da tabela na visualização da fatura no Sprint 14. Ninguém atualiza o template PDF até que um usuário relate que a fatura baixada parece diferente da tela. Agora há duas fontes de verdade, e uma delas está sempre ligeiramente errada.

Bibliotecas PDF em JavaScript do lado do cliente evitam a duplicação, mas perdem dados renderizados no servidor, dados autenticados, totais calculados no lado do servidor, e seções condicionais impulsionadas pelo ViewModel não sobrevivem à transferência para um renderer do lado do navegador. A automação de navegador sem cabeça do servidor é frágil, adiciona sobrecarga de infraestrutura, e falha de forma imprevisível em ambientes conteinerizados. Impressão em PDF pelo navegador funciona para um usuário imprimindo manualmente; não é um botão "Baixar PDF" em uma aplicação de produção.

Os cenários reais revelam o custo real: um administrador de comércio eletrônico baixando uma página de detalhes de pedido para cumprimento, um cliente exportando uma página de status do projeto de uma ferramenta de gestão de projetos, um funcionário baixando seu contracheque, um despachante imprimindo um resumo de rota. Todos esperam que o PDF pareça exatamente como o que veem na tela.

A Solução: Renderizar a View Existente, Não Uma Cópia

IronPDF permite que aplicativos ASP.NET Core renderizem uma view Razor existente — a mesma que serve o navegador — diretamente em um PDF. A ação do controlador PDF renderiza a view Razor para uma string HTML usando o motor de view padrão, passa essa string para ChromePdfRenderer.RenderHtmlAsPdf(), e retorna o resultado como um download de arquivo.

Uma view, duas saídas. Quando a view Razor muda, a saída PDF muda com ela, automaticamente, sem necessidade de coordenação. Não há templates paralelos para manter, nem soluções alternativas do lado do cliente para depurar, nem processo de navegador sem cabeça para manter vivo. A renderização roda dentro do aplicativo .NET existente como um único pacote NuGet.

Como funciona na prática

1. A View Já Existe: A Ação PDF É O Que é Novo

Uma página de detalhes de fatura em /invoices/{id} renderiza o mesmo modelo de dados esteja ela servindo um navegador ou produzindo um PDF. O modelo inclui itens de linha, totais, detalhes do cliente, e branding da empresa, todos os dados que a view precisa. O InvoicesController existente tem uma ação Details que preenche esse modelo. A ação PDF é uma irmã dela, não uma substituição.

Quando o usuário clica "Baixar PDF", a solicitação atinge /invoices/{id}/pdf. A ação PDF busca o mesmo ViewModel usando a mesma chamada de serviço, o modelo é idêntico. O que difere é o que acontece a seguir.

2. View Razor Renderizada para String HTML

Em vez de retornar um ViewResult, a ação PDF usa um serviço de renderização de view para invocar o motor Razor contra o arquivo de view e ViewModel, capturando a saída como uma string. Isso é um padrão comum em ASP.NET Core, um IViewRenderService injetado no controlador que chama ICompositeViewEngine, executa a view em um ActionContext falso, e retorna o HTML renderizado.

A string HTML renderizada é completa: todos os dados estão preenchidos, todas as seções condicionais são resolvidas, todos os nomes de classes CSS estão presentes. É o mesmo HTML que o navegador receberia, capturado no lado do servidor.

3. ChromePdfRenderer Converte String HTML para Formato PDF

using IronPdf;

[HttpGet("{id}/pdf")]
public async Task<IActionResult> DownloadInvoicePdf(int id)
{
    var model = await _invoiceService.GetInvoiceViewModelAsync(id);

    // Render the existing Razor view to an HTML string
    string html = await _viewRenderer.RenderToStringAsync("Invoices/Details", model);

    var renderer = new ChromePdfRenderer();

    renderer.RenderingOptions.CssMediaType = IronPdf.Rendering.PdfCssMediaType.Print;
    renderer.RenderingOptions.MarginTop = 15;
    renderer.RenderingOptions.MarginBottom = 15;

    PdfDocument pdf = renderer.RenderHtmlAsPdf(html);

    return File(pdf.BinaryData, "application/pdf"
        $"Invoice-{model.InvoiceNumber}.pdf");
}
using IronPdf;

[HttpGet("{id}/pdf")]
public async Task<IActionResult> DownloadInvoicePdf(int id)
{
    var model = await _invoiceService.GetInvoiceViewModelAsync(id);

    // Render the existing Razor view to an HTML string
    string html = await _viewRenderer.RenderToStringAsync("Invoices/Details", model);

    var renderer = new ChromePdfRenderer();

    renderer.RenderingOptions.CssMediaType = IronPdf.Rendering.PdfCssMediaType.Print;
    renderer.RenderingOptions.MarginTop = 15;
    renderer.RenderingOptions.MarginBottom = 15;

    PdfDocument pdf = renderer.RenderHtmlAsPdf(html);

    return File(pdf.BinaryData, "application/pdf"
        $"Invoice-{model.InvoiceNumber}.pdf");
}
Imports IronPdf
Imports Microsoft.AspNetCore.Mvc

<HttpGet("{id}/pdf")>
Public Async Function DownloadInvoicePdf(id As Integer) As Task(Of IActionResult)
    Dim model = Await _invoiceService.GetInvoiceViewModelAsync(id)

    ' Render the existing Razor view to an HTML string
    Dim html As String = Await _viewRenderer.RenderToStringAsync("Invoices/Details", model)

    Dim renderer As New ChromePdfRenderer()

    renderer.RenderingOptions.CssMediaType = IronPdf.Rendering.PdfCssMediaType.Print
    renderer.RenderingOptions.MarginTop = 15
    renderer.RenderingOptions.MarginBottom = 15

    Dim pdf As PdfDocument = renderer.RenderHtmlAsPdf(html)

    Return File(pdf.BinaryData, "application/pdf", $"Invoice-{model.InvoiceNumber}.pdf")
End Function
$vbLabelText   $csharpLabel

Documento PDF Gerado

Exemplo de PDF de saída do IronPDF CssMediaType.Print aplica quaisquer regras @media print já na folha de estilo da view: ocultando a barra de navegação, suprimindo botões de ação, e aplicando espaçamento específico para impressão, sem exigir quaisquer alterações na própria view Razor.

PontasSe a view Razor referencia folhas de estilo ou imagens por meio de caminhos relativos, configure um BaseUrlPath como o segundo parâmetro em RenderHtmlAsPdf() para que o IronPDF resolva esses ativos corretamente durante a renderização. Sem isso, referências de CSS e imagem que funcionam em contexto de navegador falharão ao carregar no renderizador do lado do servidor.

4. Ajustando a Saída do PDF Sem Tocar na View

Ajustes específicos para PDF, como números de página, margens personalizadas, cabeçalhos com o título do documento, são configurados no renderizador, não na view Razor. Isso mantém a lógica de impressão fora do template:

var renderer = new ChromePdfRenderer();

renderer.RenderingOptions.CssMediaType = IronPdf.Rendering.PdfCssMediaType.Print;
renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.A4;
renderer.RenderingOptions.MarginTop = 20;
renderer.RenderingOptions.MarginBottom = 20;
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
    HtmlFragment = @"
        <div style='font-size:9px; color:#888; text-align:center; width:100%;'>
            Invoice — Page {page} of {total-pages}
        </div>",
    DrawDividerLine = true
};

PdfDocument pdf = renderer.RenderHtmlAsPdf(html);
var renderer = new ChromePdfRenderer();

renderer.RenderingOptions.CssMediaType = IronPdf.Rendering.PdfCssMediaType.Print;
renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.A4;
renderer.RenderingOptions.MarginTop = 20;
renderer.RenderingOptions.MarginBottom = 20;
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
    HtmlFragment = @"
        <div style='font-size:9px; color:#888; text-align:center; width:100%;'>
            Invoice — Page {page} of {total-pages}
        </div>",
    DrawDividerLine = true
};

PdfDocument pdf = renderer.RenderHtmlAsPdf(html);
Imports IronPdf

Dim renderer As New ChromePdfRenderer()

renderer.RenderingOptions.CssMediaType = IronPdf.Rendering.PdfCssMediaType.Print
renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.A4
renderer.RenderingOptions.MarginTop = 20
renderer.RenderingOptions.MarginBottom = 20
renderer.RenderingOptions.HtmlFooter = New HtmlHeaderFooter With {
    .HtmlFragment = "
        <div style='font-size:9px; color:#888; text-align:center; width:100%;'>
            Invoice — Page {page} of {total-pages}
        </div>",
    .DrawDividerLine = True
}

Dim pdf As PdfDocument = renderer.RenderHtmlAsPdf(html)
$vbLabelText   $csharpLabel

Arquivo PDF de saída

Arquivo PDF com ajustes de saída personalizados A view Razor nunca precisa saber se está renderizando para um navegador ou para um PDF. A ação do controlador é responsável pela configuração específica de PDF, e a view permanece um template de exibição puro.

Benefícios no mundo real

Zero duplicação de template. A view Razor é a única fonte de verdade para o layout e conteúdo do documento. O navegador e o PDF renderizam a partir do mesmo arquivo, não há segundo template para manter e nenhum desvio para corrigir.

Adoção instantânea. Se a view já existe, a exportação PDF está a uma ação de controlador de distância. Não há necessidade de redesenhar layouts, reconstruir templates, ou portar lógica condicional para um sistema de renderização diferente.

Saída com precisão de pixel. Renderização baseada em Chromium significa que grid CSS, flexbox, fontes web, e consultas de mídia funcionam todas no PDF. A saída corresponde ao que o navegador produz, não uma aproximação degradada.

Estilização específica para impressão. Regras @media print já na folha de estilo da view controlam o que aparece no PDF: ocultando a navegação, ajustando larguras de coluna para papel, ou redispondo conteúdo. Nenhum template separado, sem estilos de impressão inline para gerenciar separadamente.

Manutenibilidade. Atualize a view Razor e tanto a saída do navegador quanto a saída do PDF refletem a mudança. Não há segundo sistema para coordenar atualizações, sem risco de uma mudança do designer alcançar o navegador mas não o PDF.

Sem custos por documento. A renderização é executada em processo dentro do aplicativo web. Não há chamadas de API externas, sem medição de uso, e nenhum modelo de custo que escala contra o volume de downloads.

Encerramento

Se a view Razor já está construída, a exportação PDF não é um novo recurso, é um novo caminho de entrega para trabalho existente. O mesmo modelo, a mesma view, a mesma estilização: a única adição é uma ação de controlador que captura a saída HTML da view e a passa por um renderizador antes de retornar como um arquivo.

Essa arquitetura mantém a base de código limpa e a saída PDF permanentemente em sincronia com o navegador. IronPDF lida com todo o ciclo de vida da geração de PDF em C# em ironpdf.com, desde a renderização HTML até salvar, transmitir, e manipular documentos. Se você está pronto para adicionar exportação de PDF às suas views Razor existentes, comece seu teste gratuito de 30 dias e valide a saída contra sua renderização atual do navegador antes de enviar o recurso.

Curtis Chau
Redator Técnico

Curtis Chau é bacharel em Ciência da Computação (Universidade Carleton) e se especializa em desenvolvimento front-end, com experiência em Node.js, TypeScript, JavaScript e React. Apaixonado por criar interfaces de usuário intuitivas e esteticamente agradáveis, Curtis gosta de trabalhar com frameworks modernos e criar manuais ...

Leia mais

Equipe de Suporte Iron

Estamos online 24 horas por dia, 5 dias por semana.
Bater papo
E-mail
Liga para mim