Pular para o conteúdo
CODECYCLEPDF Services
Como funcionaPreçoPrivacidadeCódigo abertoFAQ
EntrarCriar conta
  1. Início
  2. Guias
  3. HTML para PDF em C#

Gerar PDF a partir de HTML em C#

Guia · atualizado em 12/09/2026 · 8 min de leitura

Faturas, relatórios, contratos e comprovantes: em sistemas .NET é comum precisar gerar PDF a partir de HTML em C#. Desenhar o documento em HTML e CSS é mais rápido do que posicionar texto por coordenadas, e o mesmo layout serve para a tela e para o PDF. Este guia compara as opções mais usadas e mostra o código completo, com HttpClient e ASP.NET Core, usando a API do PDF Services.

  1. As opções no .NET
  2. Quando usar uma API
  3. Passo a passo com HttpClient
  4. Exemplo em ASP.NET Core
  5. CSS para PDF
  6. Tratamento de erros
  7. Custos e privacidade

As opções para converter HTML em PDF no .NET

Existem dois caminhos: rodar um conversor dentro da sua aplicação ou chamar um serviço pela rede. As alternativas mais conhecidas:

OpçãoComo funcionaPontos de atenção
iText (pdfHTML)Biblioteca que converte HTML e CSS direto em PDF, sem navegador.Licença AGPL ou comercial: usar dentro de um produto fechado exige avaliar a licença.
PuppeteerSharp / PlaywrightControlam um Chromium headless e "imprimem" a página em PDF.Precisam baixar e manter o navegador, consomem bastante memória e complicam containers enxutos e ambientes serverless.
wkhtmltopdf (DinkToPdf e similares)Wrapper de um executável baseado em WebKit.Projeto arquivado desde 2023, com motor de renderização antigo. Evite em projetos novos.
API HTTP (PDF Services)Você envia o HTML e recebe o PDF na resposta.Depende de rede e é cobrado por uso, mas não há nada para instalar ou atualizar no servidor.

O PDF Services usa o próprio iText pdfHTML por baixo. A diferença é que ele roda como serviço: sua aplicação não carrega a biblioteca nem se preocupa com licença, fontes, memória ou atualizações.

Quando faz sentido usar uma API

  • Você publica em Azure Functions, AWS Lambda ou containers mínimos, onde instalar um Chromium é caro ou impossível.
  • O volume é variável e você prefere pagar por PDF em vez de dimensionar servidores para picos.
  • Você não quer lidar com dependências nativas, fontes do sistema operacional e atualizações de segurança do conversor.

Se você precisa executar JavaScript da página, como gráficos montados no navegador, um navegador headless é a ferramenta certa. Para documentos de negócio montados no servidor, HTML e CSS bastam.

Passo a passo: gerar o PDF com HttpClient

1. Crie a conta e a chave de API

Cadastre a empresa, confirme o e-mail e crie uma chave em Chaves de API no painel. A chave aparece uma única vez: guarde-a como segredo, por exemplo em variável de ambiente, User Secrets ou Azure Key Vault, nunca no código-fonte.

2. Envie o HTML e salve o PDF

O exemplo abaixo é um app de console do .NET 8 ou superior. O corpo da requisição é o próprio HTML, com Content-Type: text/html; charset=utf-8:

Program.cs
using System.Text;

var apiKey = Environment.GetEnvironmentVariable("PDFSERVICES_API_KEY")
    ?? throw new InvalidOperationException("Defina a variável PDFSERVICES_API_KEY.");

var html = """
    <!doctype html>
    <html lang="pt-BR">
    <head>
      <meta charset="utf-8">
      <style>
        @page { size: A4; margin: 2cm; }
        body { font-family: sans-serif; }
      </style>
    </head>
    <body><h1>Olá, PDF!</h1></body>
    </html>
    """;

using var http = new HttpClient { BaseAddress = new Uri("https://api.pdfservices.sistema.site") };
http.DefaultRequestHeaders.Add("X-Api-Key", apiKey);

using var content = new StringContent(html, Encoding.UTF8, "text/html");
using var response = await http.PostAsync("/v1/html2pdf/html", content);

if (!response.IsSuccessStatusCode)
{
    var erro = await response.Content.ReadAsStringAsync();
    throw new InvalidOperationException($"Falha {(int)response.StatusCode}: {erro}");
}

await File.WriteAllBytesAsync("documento.pdf", await response.Content.ReadAsByteArrayAsync());
Console.WriteLine($"Cobrado: R$ {response.Headers.GetValues("X-Charged-Amount").First()}");

A resposta traz o PDF em application/pdf e os headers X-Transaction-Id, X-Charged-Amount (valor cobrado) e X-Balance (saldo restante).

3. Se preferir, envie JSON

C#
// O formato json é útil quando o HTML já está em um objeto ou vem de outro serviço.
using var response = await http.PostAsJsonAsync("/v1/html2pdf/json", new { html });

Segurança: chame a API sempre a partir do servidor. Se a chave aparecer em código que roda no navegador ou em um app móvel, qualquer pessoa pode usá-la e consumir seus créditos.

Exemplo em ASP.NET Core: devolvendo o PDF para o usuário

Em uma API web, registre um HttpClient nomeado com IHttpClientFactory e devolva o PDF com Results.File. A chave fica em appsettings ou, melhor, em User Secrets ou variáveis de ambiente (PdfServices__ApiKey):

Program.cs (ASP.NET Core)
using System.Net;
using System.Text;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddHttpClient("PdfServices", client =>
{
    client.BaseAddress = new Uri("https://api.pdfservices.sistema.site");
    client.DefaultRequestHeaders.Add("X-Api-Key", builder.Configuration["PdfServices:ApiKey"]);
});

var app = builder.Build();

app.MapGet("/faturas/{numero}/pdf", async (string numero, IHttpClientFactory factory) =>
{
    // Todo dado vindo do usuário deve ser codificado antes de entrar no HTML.
    var html = $"""
        <!doctype html>
        <html lang="pt-BR">
        <head><meta charset="utf-8"></head>
        <body><h1>Fatura {WebUtility.HtmlEncode(numero)}</h1></body>
        </html>
        """;

    var client = factory.CreateClient("PdfServices");
    using var response = await client.PostAsync("/v1/html2pdf/html", new StringContent(html, Encoding.UTF8, "text/html"));

    if (!response.IsSuccessStatusCode)
    {
        return Results.Problem($"Falha ao gerar o PDF ({(int)response.StatusCode}).");
    }

    var pdf = await response.Content.ReadAsByteArrayAsync();
    return Results.File(pdf, "application/pdf", $"fatura-{numero}.pdf");
});

app.Run();

Para documentos maiores, monte o HTML com Razor, por exemplo com uma view renderizada para string ou uma biblioteca de templates. O importante é codificar todo dado vindo do usuário (WebUtility.HtmlEncode) para evitar injeção de HTML no documento.

CSS para PDF: tamanho da página, cabeçalho, rodapé e quebras

O motor de conversão entende CSS de impressão (paged media). É com ele que você controla o documento, sem nada específico de C#:

estilo.css (dentro de uma tag <style>)
@page {
  size: A4;
  margin: 2.5cm 2cm;
  @top-center { content: "Relatório mensal"; }
  @bottom-right { content: "Página " counter(page) " de " counter(pages); }
}

.nova-pagina { page-break-before: always; }

/* Repete o cabeçalho da tabela em todas as páginas */
thead { display: table-header-group; }
  • Tamanho e margens: @page { size: A4; }, A4 landscape, Letter ou medidas como 21cm 29.7cm.
  • Cabeçalho e rodapé: as caixas de margem (@top-center, @bottom-right etc.) com counter(page) e counter(pages) geram o "Página 1 de 3".
  • Quebras: page-break-before, page-break-after e page-break-inside: avoid para não cortar blocos ao meio.
  • Imagens: embutidas como data: URI ou por URL https pública, em JPG ou PNG.
  • Fontes: as padrão já cobrem acentos; para a sua fonte, use @font-face com data: URI. Fontes por URL, como as do Google Fonts, não são baixadas.
  • JavaScript não é executado: monte o HTML final no servidor. Para gráficos, gere uma imagem PNG antes.

Tratamento de erros

Quando algo dá errado, a API responde com um JSON {"error": "...", "message": "..."}. Os casos que valem tratar no código:

HTTPCódigoO que fazer
401invalid_api_keyConfira a chave configurada; ela pode ter sido excluída no painel.
402insufficient_balanceSaldo insuficiente: adicione créditos. Não adianta repetir a chamada.
413payload_too_largeO corpo passou de 1 MB. Reduza imagens embutidas ou use URLs https.
422conversion_failedO HTML não pôde ser convertido. Revise o documento; a falha não é cobrada.
503busyMuitas chamadas simultâneas na mesma conta: repita com espera crescente.

No .NET, o pacote Microsoft.Extensions.Http.Resilience (ou o Polly) resolve as novas tentativas no próprio HttpClient. Limite as tentativas ao status 503 e a falhas de rede: repetir 401, 402 ou 422 não muda o resultado.

Custos e privacidade

O PDF Services cobra R$ 0,001 por conversão bem-sucedida, com créditos pré-pagos e sem mensalidade: mil PDFs custam R$ 1,00. Conversões com erro não são cobradas.

O HTML enviado e o PDF gerado são processados só em memória e nunca são armazenados nem registrados em logs. Ficam registrados apenas metadados da transação, como data, tamanho e valor cobrado. Detalhes na Política de Privacidade. Todo o código do serviço é aberto, sob a licença AGPL v3, e pode ser auditado no GitHub.

Gere seu primeiro PDF agora

Crie a conta da sua empresa, gere uma chave no painel e rode o exemplo acima. Pelo painel também dá para testar a conversão antes de escrever uma linha de código.

Criar conta Já tenho conta · Entrar

Outros guias

  • Gerar PDF a partir de HTML em Node.js
  • Gerar PDF a partir de HTML em Python
  • Referência rápida da API, com exemplos em PHP e cURL

HTML para PDF em C# · HTML para PDF em Node.js · HTML para PDF em Python

Termos de Uso · Política de Privacidade · Código-fonte (GitHub) · © CODECYCLE · Software livre sob AGPL v3