
Como Criar um PDF em ASP.NET C# com IronPDF
O envio e o download de arquivos PDF no ASP.NET Core exigem o tratamento de dados binários, o gerenciamento de ações do controlador e — opcionalmente — o processamento dos documentos no servidor antes do armazenamento ou da entrega. Com o IronPDF , você pode ir além do simples armazenamento de arquivos, aplicando marcas d'água, gerando PDFs a partir de HTML e retornando documentos processados aos usuários, tudo dentro do seu pipeline MVC existente. Este guia orienta você em cada etapa da criação de um fluxo de trabalho completo de upload e download em C# usando o .NET 10.
Como instalar o IronPDF em um projeto ASP.NET Core ?
Antes de escrever qualquer lógica de upload ou download, adicione o IronPDF ao seu projeto usando o Gerenciador de Pacotes NuGet ou a CLI do .NET . Use Install-Package IronPdf no Console do Gerenciador de Pacotes ou execute os comandos CLI abaixo para criar um novo projeto MVC e adicionar todos os pacotes necessários de uma vez.
dotnet new mvc -n PdfManager --framework net10.0
cd PdfManager
dotnet add package IronPdf
dotnet add package Microsoft.EntityFrameworkCore.Sqlite
dotnet add package Microsoft.EntityFrameworkCore.Design
Uma vez instalado, IronPDF fornece acesso a ChromePdfRenderer para gerar PDFs a partir de HTML, PdfDocument para carregar e manipular arquivos existentes, e uma gama de ferramentas de edição incluindo marcas d'água, carimbos e assinaturas digitais. Você pode consultar a página completa do pacote NuGet IronPDF para obter o histórico de versões e notas de compatibilidade.
Configurando o projeto
Adicione uma constante de caminho de armazenamento a Program.cs e registre seu ApplicationDbContext com o contêiner de injeção de dependência. A estrutura do seu projeto incluirá um Controllers/PdfController.cs, um Models/PdfFileModel.cs e um Data/ApplicationDbContext.cs antes de escrever qualquer lógica específica de PDF.
Como criar um modelo de banco de dados para armazenamento de PDFs?
A base de qualquer sistema de upload de PDF é uma classe de modelo que mapeia para uma tabela de banco de dados. O seguinte registro em C# captura os campos essenciais: nome do arquivo, tipo de conteúdo, dados binários brutos e um registro de data e hora do upload.
public class PdfFileModel
{
public int Id { get; set; }
public string FileName { get; set; } = string.Empty;
public string ContentType { get; set; } = "application/pdf";
public byte[] FileData { get; set; } = Array.Empty<byte>();
public DateTime UploadedDate { get; set; } = DateTime.UtcNow;
}Public Class PdfFileModel
Public Property Id As Integer
Public Property FileName As String = String.Empty
Public Property ContentType As String = "application/pdf"
Public Property FileData As Byte() = Array.Empty(Of Byte)()
Public Property UploadedDate As DateTime = DateTime.UtcNow
End ClassFileData armazena o PDF como um grande objeto binário (BLOB). Essa abordagem mantém os documentos isolados dentro do banco de dados, simplificando os backups e tornando as consultas mais diretas. Para cenários de alto volume ou arquivos grandes, considere armazenar apenas o caminho do arquivo no banco de dados e gravar o binário em um bucket de armazenamento em nuvem, como o Azure Blob Storage ou o Amazon S3 .
Configurando o Entity Framework Core
Registre o modelo com o EF Core adicionando uma propriedade DbSet<PdfFileModel> ao seu ApplicationDbContext:
using Microsoft.EntityFrameworkCore;
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options) { }
public DbSet<PdfFileModel> PdfFiles { get; set; }
}Imports Microsoft.EntityFrameworkCore
Public Class ApplicationDbContext
Inherits DbContext
Public Sub New(options As DbContextOptions(Of ApplicationDbContext))
MyBase.New(options)
End Sub
Public Property PdfFiles As DbSet(Of PdfFileModel)
End ClassExecute dotnet ef migrations add InitialCreate seguido de dotnet ef database update para criar o esquema. Entity Framework Core mapeia byte[] para uma coluna varbinary(max) no SQL Server ou uma coluna BLOB no SQLite automaticamente -- não é necessário SQL manual.
Como faço para carregar arquivos PDF em um controlador ASP.NET Core ?
A ação do controlador que lida com uploads recebe um parâmetro IFormFile de um formulário HTML usando enctype="multipart/form-data". A ação lê o fluxo em um MemoryStream, converte-o em um array de bytes e persiste o resultado através do Entity Framework Core.
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
public class PdfController : Controller
{
private readonly ApplicationDbContext _context;
public PdfController(ApplicationDbContext context)
{
_context = context;
}
[HttpPost]
public async Task<IActionResult> Upload(IFormFile file)
{
if (file is null || file.Length == 0)
return BadRequest("No file selected.");
if (!file.ContentType.Equals("application/pdf", StringComparison.OrdinalIgnoreCase))
return BadRequest("Only PDF files are accepted.");
using var stream = new MemoryStream();
await file.CopyToAsync(stream);
var pdfFile = new PdfFileModel
{
FileName = Path.GetFileName(file.FileName),
ContentType = file.ContentType,
FileData = stream.ToArray(),
UploadedDate = DateTime.UtcNow
};
_context.PdfFiles.Add(pdfFile);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
public async Task<IActionResult> Index()
{
var files = await _context.PdfFiles
.Select(f => new { f.Id, f.FileName, f.UploadedDate })
.ToListAsync();
return View(files);
}
}Imports Microsoft.AspNetCore.Mvc
Imports Microsoft.EntityFrameworkCore
Imports System.IO
Imports System.Threading.Tasks
Public Class PdfController
Inherits Controller
Private ReadOnly _context As ApplicationDbContext
Public Sub New(context As ApplicationDbContext)
_context = context
End Sub
<HttpPost>
Public Async Function Upload(file As IFormFile) As Task(Of IActionResult)
If file Is Nothing OrElse file.Length = 0 Then
Return BadRequest("No file selected.")
End If
If Not file.ContentType.Equals("application/pdf", StringComparison.OrdinalIgnoreCase) Then
Return BadRequest("Only PDF files are accepted.")
End If
Using stream As New MemoryStream()
Await file.CopyToAsync(stream)
Dim pdfFile As New PdfFileModel With {
.FileName = Path.GetFileName(file.FileName),
.ContentType = file.ContentType,
.FileData = stream.ToArray(),
.UploadedDate = DateTime.UtcNow
}
_context.PdfFiles.Add(pdfFile)
Await _context.SaveChangesAsync()
End Using
Return RedirectToAction(NameOf(Index))
End Function
Public Async Function Index() As Task(Of IActionResult)
Dim files = Await _context.PdfFiles _
.Select(Function(f) New With {f.Id, f.FileName, f.UploadedDate}) _
.ToListAsync()
Return View(files)
End Function
End ClassValidando os arquivos enviados
Valide sempre o tipo de conteúdo antes de processá-lo. Verificar file.ContentType protege contra usuários que acidentalmente carregam conteúdo não-PDF. Para validação mais forte, leia os primeiros quatro bytes do fluxo e verifique o número mágico do PDF (%PDF). Você também deve impor um tamanho máximo de arquivo -- tipicamente 10 MB para fluxos de trabalho de documentos gerais -- verificando file.Length antes de copiar o fluxo.
O formulário HTML que desencadeia essa ação precisa de dois atributos: method="post" e enctype="multipart/form-data". Sem a especificação do tipo de codificação, os navegadores enviam o nome do arquivo como texto simples em vez do conteúdo binário. Adicione um elemento <input type="file" name="file" accept=".pdf" /> e um botão de envio dentro da tag de formulário apontando para /Pdf/Upload.

Como adicionar uma marca d'água a um PDF carregado antes de salvá-lo?
Processar arquivos no servidor antes do armazenamento é um dos usos mais práticos dos recursos de marca d'água do IronPDF . Você pode marcar todos os documentos recebidos com uma etiqueta "CONFIDENCIAL", um logotipo da empresa ou um aviso de "RASCUNHO" antes mesmo que os dados cheguem ao banco de dados.
[HttpPost]
public async Task<IActionResult> UploadWithWatermark(IFormFile file)
{
if (file is null || file.Length == 0)
return BadRequest("No file selected.");
using var stream = new MemoryStream();
await file.CopyToAsync(stream);
byte[] originalBytes = stream.ToArray();
// Load the uploaded file into IronPDF
var pdf = new IronPdf.PdfDocument(originalBytes);
// Apply an HTML watermark centered on every page
pdf.ApplyWatermark(
"<h2 style='color:red;opacity:0.4'>CONFIDENTIAL</h2>",
rotation: 45,
opacity: 60,
verticalAlignment: IronPdf.Editing.VerticalAlignment.Middle,
horizontalAlignment: IronPdf.Editing.HorizontalAlignment.Center
);
var pdfFile = new PdfFileModel
{
FileName = Path.GetFileName(file.FileName),
ContentType = "application/pdf",
FileData = pdf.BinaryData,
UploadedDate = DateTime.UtcNow
};
_context.PdfFiles.Add(pdfFile);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}Imports System.IO
Imports System.Threading.Tasks
Imports Microsoft.AspNetCore.Mvc
<HttpPost>
Public Async Function UploadWithWatermark(file As IFormFile) As Task(Of IActionResult)
If file Is Nothing OrElse file.Length = 0 Then
Return BadRequest("No file selected.")
End If
Using stream As New MemoryStream()
Await file.CopyToAsync(stream)
Dim originalBytes As Byte() = stream.ToArray()
' Load the uploaded file into IronPDF
Dim pdf = New IronPdf.PdfDocument(originalBytes)
' Apply an HTML watermark centered on every page
pdf.ApplyWatermark(
"<h2 style='color:red;opacity:0.4'>CONFIDENTIAL</h2>",
rotation:=45,
opacity:=60,
verticalAlignment:=IronPdf.Editing.VerticalAlignment.Middle,
horizontalAlignment:=IronPdf.Editing.HorizontalAlignment.Center
)
Dim pdfFile As New PdfFileModel With {
.FileName = Path.GetFileName(file.FileName),
.ContentType = "application/pdf",
.FileData = pdf.BinaryData,
.UploadedDate = DateTime.UtcNow
}
_context.PdfFiles.Add(pdfFile)
Await _context.SaveChangesAsync()
Return RedirectToAction(NameOf(Index))
End Using
End FunctionOpções de configuração da marca d'água
O método ApplyWatermark do IronPDF aceita uma string HTML, o que significa que sua marca d'água pode incluir qualquer HTML válido e CSS inline -- gradientes, fontes personalizadas, texto rotacionado ou até mesmo ícones SVG embutidos. O parâmetro rotation rotaciona a marca d'água ao longo da diagonal da página, enquanto opacity controla a transparência de 0 (invisível) a 100 (totalmente opaco).
Além de marcas d'água, o mesmo objeto PdfDocument expõe métodos para adicionar cabeçalhos e rodapés, estampar imagens e editar campos de formulário existentes. Você pode encadear múltiplas etapas de processamento antes de chamar pdf.BinaryData para recuperar o array de bytes final.

Como faço para baixar arquivos PDF armazenados no banco de dados?
Para servir de volta um PDF armazenado ao navegador, recupere o registro por ID e retorne um FileResult. O método auxiliar File do ASP.NET Core define o cabeçalho Content-Type correto e ativa a caixa de diálogo de download do navegador com o nome de arquivo original.
public async Task<IActionResult> Download(int id)
{
var pdfFile = await _context.PdfFiles.FindAsync(id);
if (pdfFile is null)
return NotFound();
return File(pdfFile.FileData, pdfFile.ContentType, pdfFile.FileName);
}Imports System.Threading.Tasks
Imports Microsoft.AspNetCore.Mvc
Public Async Function Download(id As Integer) As Task(Of IActionResult)
Dim pdfFile = Await _context.PdfFiles.FindAsync(id)
If pdfFile Is Nothing Then
Return NotFound()
End If
Return File(pdfFile.FileData, pdfFile.ContentType, pdfFile.FileName)
End FunctionExibindo uma lista de downloads na visualização.
A ação Index recupera todos os registros de arquivos armazenados e os passa para uma visão Razor. Uma tabela HTML simples exibe o nome do arquivo, a data de upload e um link para download de cada registro.
<table class="content__data-table" data-content-table>
<caption>Uploaded PDF Files</caption>
<thead>
<tr>
<th>File Name</th>
<th>Uploaded</th>
<th>Action</th>
</tr>
</thead>
<tbody>
@foreach (var item in Model)
{
<tr>
<td>@item.FileName</td>
<td>@item.UploadedDate.ToString("yyyy-MM-dd HH:mm")</td>
<td><a href="/Pdf/Download/@item.Id">Download</a></td>
</tr>
}
</tbody>
</table>netA sobrecarga return File(bytes, contentType, fileName) define tanto Content-Type: application/pdf quanto Content-Disposition: attachment; cabeçalhos filename="...". Se você quiser que o navegador abra o PDF inline em vez de solicitar um download, use return File(bytes, contentType) sem o terceiro argumento -- isso omite a instrução Content-Disposition: attachment.

Armazenamento em sistema de arquivos como alternativa
Em implantações de grande porte, armazenar dados binários brutos no banco de dados aumenta o tamanho das linhas e pode tornar as consultas mais lentas. Uma alternativa é gravar o arquivo em um diretório no disco — ou em um provedor de nuvem — e armazenar apenas o caminho relativo no banco de dados. Substitua FileData byte[] por FilePath string, escreva System.IO.File.WriteAllBytesAsync(path, bytes) durante o upload e leia System.IO.File.ReadAllBytesAsync(path) durante o download. Ambos os caminhos convergem na mesma chamada return File(...) no controlador.
Como gerar documentos PDF sob demanda e disponibilizá-los para download?
Você não está limitado a servir arquivos pré-armazenados. A conversão de HTML para PDF do IronPDF permite gerar documentos dinamicamente a partir de dados sob demanda, o que é útil para faturas, relatórios, certificados e exportação de dados.
public IActionResult GenerateInvoice(int orderId)
{
// Build HTML content from your data model
string html = $@"
<html>
<body style='font-family: Arial, sans-serif; padding: 40px;'>
<h1>Invoice #{orderId}</h1>
<p>Generated: {DateTime.UtcNow:yyyy-MM-dd HH:mm} UTC</p>
<table border='1' cellpadding='8'>
<tr><th>Item</th><th>Qty</th><th>Price</th></tr>
<tr><td>IronPDF License</td><td>1</td><td>$999</td></tr>
</table>
</body>
</html>";
var renderer = new IronPdf.ChromePdfRenderer();
using var pdf = renderer.RenderHtmlAsPdf(html);
return File(pdf.BinaryData, "application/pdf", $"invoice-{orderId}.pdf");
}
Opções de renderização para PDFs sob demanda
ChromePdfRenderer produz uma saída com precisão de pixel usando o mesmo mecanismo de renderização Chromium que alimenta o Google Chrome. Isso significa que qualquer CSS que você possa exibir em um navegador -- layouts flexbox, grids, fontes personalizadas, gráficos SVG -- será renderizado corretamente no PDF gerado. Você pode definir tamanho de papel, margens e orientação através da propriedade RenderingOptions antes de chamar RenderHtmlAsPdf.
Para documentos mais complexos, passe uma URL completa para RenderUrlAsPdf em vez de uma string HTML. O IronPDF carregará a página em um navegador sem interface gráfica, executará o JavaScript, aplicará os estilos e converterá o DOM totalmente renderizado em PDF. Consulte o guia de conversão de HTML para PDF para obter o conjunto completo de opções de renderização, incluindo cabeçalhos, rodapés e numeração de páginas personalizados.

Como mesclar vários arquivos PDF no ASP.NET Core?
Além de operações com um único arquivo, você pode precisar combinar vários documentos carregados em um só. A capacidade de mesclagem de PDF do IronPDF aceita uma lista de objetos PdfDocument e retorna um único arquivo mesclado.
public async Task<IActionResult> MergeAll()
{
var allFiles = await _context.PdfFiles.ToListAsync();
if (allFiles.Count < 2)
return BadRequest("At least two files are required for merging.");
var documents = allFiles
.Select(f => new IronPdf.PdfDocument(f.FileData))
.ToList();
using var merged = IronPdf.PdfDocument.Merge(documents);
return File(merged.BinaryData, "application/pdf", "merged.pdf");
}Imports System.Threading.Tasks
Imports Microsoft.AspNetCore.Mvc
Public Async Function MergeAll() As Task(Of IActionResult)
Dim allFiles = Await _context.PdfFiles.ToListAsync()
If allFiles.Count < 2 Then
Return BadRequest("At least two files are required for merging.")
End If
Dim documents = allFiles _
.Select(Function(f) New IronPdf.PdfDocument(f.FileData)) _
.ToList()
Using merged = IronPdf.PdfDocument.Merge(documents)
Return File(merged.BinaryData, "application/pdf", "merged.pdf")
End Using
End FunctionSeparar páginas de um PDF
A operação inversa -- extraindo um subconjunto de páginas -- usa CopyPages. Carregue um PdfDocument a partir dos bytes armazenados, chame source.CopyPages(startIndex, endIndex) com índices de páginas baseados em zero e retorne o PdfDocument.BinaryData resultante como um FileResult. Esse padrão é útil para pré-visualizações de paginação, divisão de relatórios com várias seções ou extração de uma página de capa para geração de miniaturas. Você também pode aplicar assinaturas digitais à saída mesclada ou dividida antes de disponibilizá-la aos usuários.
Como lidar com o envio seguro de arquivos grandes?
Arquivos PDF grandes exigem configuração adicional no nível do middleware do ASP.NET Core . Por padrão, o limite de tamanho do corpo da requisição é definido em aproximadamente 28 MB. Para levantá-lo, chame builder.Services.Configure<FormOptions> para definir MultipartBodyLengthLimit e builder.WebHost.ConfigureKestrel para definir Limits.MaxRequestBodySize -- ambos para a contagem de bytes desejada, como 50 * 1024 * 1024 para 50 MB -- em Program.cs antes de builder.Build().
Além dos limites de tamanho, aplique estas práticas de segurança a cada ponto de upload: valide o cabeçalho do tipo de conteúdo, inspecione os primeiros bytes do fluxo para o número mágico %PDF, examine scripts embutidos usando a API de inspeção de documentos do IronPDF e armazene arquivos processados fora da raiz web para que nunca sejam servidos como conteúdo estático diretamente. A documentação de segurança do ASP.NET Core aborda técnicas adicionais de reforço de segurança, incluindo validação de tokens antifalsificação e integração com verificação de vírus.
Transmissão contínua de arquivos grandes para evitar sobrecarga de memória.
Quando arquivos excederem 10 MB, ler todo o fluxo em um MemoryStream antes do processamento pode aumentar o uso de memória significativamente. Use IronPdf.PdfDocument.FromStream para carregar diretamente do fluxo de solicitação sempre que possível, ou escreva em um caminho de arquivo temporário e carregue do disco:
string tempPath = Path.GetTempFileName();
await using (var fs = System.IO.File.Create(tempPath))
{
await file.CopyToAsync(fs);
}
using var pdf = new IronPdf.PdfDocument(tempPath);
// process...
System.IO.File.Delete(tempPath);Imports System.IO
Imports IronPdf
Dim tempPath As String = Path.GetTempFileName()
Using fs As FileStream = System.IO.File.Create(tempPath)
Await file.CopyToAsync(fs)
End Using
Using pdf As PdfDocument = New IronPdf.PdfDocument(tempPath)
' process...
End Using
System.IO.File.Delete(tempPath)Esse padrão mantém as alocações de memória heap baixas e funciona bem com filas de processamento em segundo plano, onde os arquivos são processados de forma assíncrona após a resposta HTTP já ter sido enviada. Explore a documentação do IronPDF para obter padrões adicionais de processamento assíncrono.
Quais são os seus próximos passos?
Agora você tem uma base completa para fazer upload, processar, armazenar e baixar arquivos PDF em um aplicativo ASP.NET Core MVC com suporte do IronPDF. A partir daqui, considere as seguintes orientações para expandir o fluxo de trabalho.
Amplie as capacidades de processamento. O IronPDF oferece suporte ao preenchimento e leitura de campos de formulários PDF , à extração de texto e imagens com a API de extração de texto de PDF e à conversão de páginas PDF em imagens para visualização em miniatura. Cada uma dessas funcionalidades se integra ao mesmo padrão de controlador mostrado acima.
Adicione assinaturas digitais. Assine cada documento gerado ou carregado com uma assinatura digital usando um certificado X.509 antes de armazená-lo. Os PDFs assinados contêm metadados invioláveis que atendem a muitos requisitos de conformidade.
Escalone o armazenamento para a nuvem. Substitua a coluna de banco de dados local byte[] por uma referência do Azure Blob Storage ou Amazon S3. Após a aplicação da marca d'água, os bytes processados são enviados para o armazenamento em nuvem, e apenas o URI é salvo no banco de dados — isso reduz drasticamente o tamanho das linhas do banco de dados e possibilita a entrega via CDN.
Inicie um teste gratuito. Visite a página de licença de avaliação do IronPDF para obter uma chave de avaliação de 30 dias com acesso a todos os recursos. Você também pode navegar pela visão geral completa dos recursos do IronPDF para entender o escopo total das funcionalidades de PDF disponíveis em seu aplicativo .NET , ou consultar a página de preços e licenciamento quando estiver pronto para a implantação em produção.

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 bem estruturados e visualmente atraentes.
Artigos relacionados


