Como criar uma API PDF em .NET usando o IronPDF
Ao trabalhar com aplicações modernas, desenvolvedores .NET como você podem precisar criar um serviço centralizado de geração de PDFs. Seja para gerar faturas, relatórios, certificados ou contratos, ter uma API .NET dedicada para PDFs pode ser muito útil para gerenciar arquivos PDF com eficiência. Então, como isso pode melhorar suas tarefas de geração de PDFs? Isso é feito ao proporcionar consistência, facilidade de manutenção e escalabilidade em seus aplicativos para desktop e web. Nunca foi tão fácil gerenciar o conteúdo de documentos, páginas de PDF e campos de formulário em PDF.
Neste tutorial, você aprenderá como criar uma API de PDF pronta para produção usando ASP.NET Core e IronPDF , uma poderosa biblioteca de PDF for .NET . Criaremos endpoints RESTful capazes de gerar PDFs a partir de HTML, mesclar documentos, adicionar marcas d'água e lidar com diversos cenários reais de geração de PDFs em sua API Web.
Por que criar uma API dedicada para PDFs?
Antes de analisarmos o código, vamos entender por que criar uma API dedicada para PDFs faz sentido:
- Lógica centralizada: Toda a lógica de geração de PDFs reside em um único local, facilitando a manutenção e as atualizações.
- Arquitetura de microsserviços: Perfeita para arquiteturas orientadas a serviços onde diferentes aplicações precisam de recursos de PDF.
- Otimização de desempenho: Facilita a escalabilidade e a otimização de um serviço dedicado para arquivos PDF grandes, com várias páginas e dados dinâmicos.
- Independente de linguagem: Qualquer aplicação cliente pode consumir a API, independentemente da linguagem de programação.
- Saída consistente: Garante que todos os documentos PDF em sua organização mantenham layout, formatação de parágrafos e conteúdo consistentes.
Pronto para começar a construir? Baixe a versão de avaliação gratuita do IronPDF e siga este tutorial para criar arquivos PDF programaticamente em seus projetos .NET Framework .
IronPDF: A Biblioteca PDF Completa for .NET
O IronPDF se destaca como a principal biblioteca de PDF para desenvolvedores .NET , oferecendo um conjunto abrangente de recursos que tornam a geração de PDFs em projetos de API Web simples e confiável. Ele é baseado em um mecanismo de renderização do Chrome, que garante conversões de HTML para PDF com perfeição de pixels, muitas vezes com apenas algumas linhas de código. Ele faz tudo isso mantendo o estilo, a execução do JavaScript e os layouts responsivos.
Principais funcionalidades que tornam o IronPDF ideal para o desenvolvimento de APIs PDF em .NET :
- Renderização baseada no Chrome: Utiliza o mecanismo de renderização do Google Chrome para converter documentos PDF a partir de conteúdo HTML com precisão, oferecendo suporte completo para imagens incorporadas e outros recursos da web.
- Conjunto de recursos avançados: Suporta a edição de documentos novos e existentes com assinaturas digitais , formulários PDF, anotações , criptografia, compressão e muito mais.
- Crie documentos PDF seguros: gerencie conteúdo PDF confidencial com criptografia, assinaturas digitais e proteção de documentos.
- Vários formatos de entrada: utilize HTML, URLs, imagens e documentos do Office para criar documentos PDF.
- Manipulação avançada: Mescle páginas de PDF, divida documentos, aplique marcas d'água, crie formulários PDF interativos e manipule arquivos PDF programaticamente.
- Suporte multiplataforma: funciona em plataformas Windows, Linux , macOS, Docker e nuvem.
- Desempenho otimizado: operações assíncronas , gerenciamento eficiente de memória e renderização rápida.
Como configurar seu projeto de API de documentos PDF?
Vamos começar criando um novo projeto de API Web ASP.NET Core e instalando os pacotes necessários.
Pré-requisitos
- SDK do .NET 6.0 ou posterior
- Visual Studio 2022 ou Visual Studio Code
- Postman ou ferramenta similar para testes de API para testar sua API REST de PDF
Criando o Projeto
Primeiro, vamos criar o projeto no qual construiremos nossa ferramenta de geração de PDF.
dotnet new webapi -n PdfApiService
cd PdfApiService
Instalando o IronPDF
O próximo passo é adicionar o IronPDF ao seu projeto via NuGet:
dotnet add package IronPdf
Ou, utilizando o Console do Gerenciador de Pacotes NuGet no Visual Studio:
Install-Package IronPdf
Estrutura do Projeto
Um aspecto essencial do desenvolvimento em C# é manter uma pasta de projeto limpa e bem estruturada. Por exemplo:
Como criar seu primeiro endpoint de PDF?
Vamos criar um endpoint simples que converta HTML para o formato PDF. Primeiro, crie a interface de serviço e a implementação:
Criando o serviço de PDF
Primeiro, adicionaremos o seguinte ao nosso arquivo IPdfService.cs:
public interface IPdfService
{
byte[] GeneratePdfFromHtml(string htmlContent);
byte[] GeneratePdfFromUrl(string url);
}
public interface IPdfService
{
byte[] GeneratePdfFromHtml(string htmlContent);
byte[] GeneratePdfFromUrl(string url);
}
Public Interface IPdfService
Function GeneratePdfFromHtml(htmlContent As String) As Byte()
Function GeneratePdfFromUrl(url As String) As Byte()
End Interface
No arquivo PdfService.cs, adicionaremos o seguinte:
using IronPdf;
public class PdfService : IPdfService
{
private readonly ChromePdfRenderer _renderer;
public PdfService()
{
_renderer = new ChromePdfRenderer();
// Configure rendering options for optimal PDF generation in .NET
_renderer.RenderingOptions.MarginTop = 20;
_renderer.RenderingOptions.MarginBottom = 20;
_renderer.RenderingOptions.PrintHtmlBackgrounds = true;
}
public byte[] GeneratePdfFromHtml(string htmlContent)
{
// Generate PDF from HTML using the .NET PDF API
var pdf = _renderer.RenderHtmlAsPdf(htmlContent);
return pdf.BinaryData;
}
public byte[] GeneratePdfFromUrl(string url)
{
// Convert URL to PDF in the REST API
var pdf = _renderer.RenderUrlAsPdf(url);
return pdf.BinaryData;
}
}
using IronPdf;
public class PdfService : IPdfService
{
private readonly ChromePdfRenderer _renderer;
public PdfService()
{
_renderer = new ChromePdfRenderer();
// Configure rendering options for optimal PDF generation in .NET
_renderer.RenderingOptions.MarginTop = 20;
_renderer.RenderingOptions.MarginBottom = 20;
_renderer.RenderingOptions.PrintHtmlBackgrounds = true;
}
public byte[] GeneratePdfFromHtml(string htmlContent)
{
// Generate PDF from HTML using the .NET PDF API
var pdf = _renderer.RenderHtmlAsPdf(htmlContent);
return pdf.BinaryData;
}
public byte[] GeneratePdfFromUrl(string url)
{
// Convert URL to PDF in the REST API
var pdf = _renderer.RenderUrlAsPdf(url);
return pdf.BinaryData;
}
}
Imports IronPdf
Public Class PdfService
Implements IPdfService
Private ReadOnly _renderer As ChromePdfRenderer
Public Sub New()
_renderer = New ChromePdfRenderer()
' Configure rendering options for optimal PDF generation in .NET
_renderer.RenderingOptions.MarginTop = 20
_renderer.RenderingOptions.MarginBottom = 20
_renderer.RenderingOptions.PrintHtmlBackgrounds = True
End Sub
Public Function GeneratePdfFromHtml(htmlContent As String) As Byte()
' Generate PDF from HTML using the .NET PDF API
Dim pdf = _renderer.RenderHtmlAsPdf(htmlContent)
Return pdf.BinaryData
End Function
Public Function GeneratePdfFromUrl(url As String) As Byte()
' Convert URL to PDF in the REST API
Dim pdf = _renderer.RenderUrlAsPdf(url)
Return pdf.BinaryData
End Function
End Class
O PdfService lida com o processo principal de conversão de HTML em PDF. Utilizando o ChromePdfRenderer do IronPDF, esta classe é configurada com valores padrão adequados, como margens de página e renderização de fundo, para produzir um documento final refinado.
Quando o controlador envia HTML bruto, o serviço usa o IronPDF para renderizá-lo em um PDF de qualidade profissional e retorna o resultado como dados em bytes, prontos para download. Além disso, também pode lidar com páginas da web inteiras, convertendo um URL diretamente em PDF.
Criando o Controlador
Agora é hora de criar o controlador para nossa API. Isso fornecerá um endpoint de API capaz de gerar arquivos PDF a partir de HTML. Em seguida, será possível baixar e salvar documentos PDF em seu sistema para uso posterior ou compartilhamento.
// Controllers/PdfController.cs
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("api/[controller]")]
public class PdfController : ControllerBase
{
private readonly IPdfService _pdfService;
public PdfController(IPdfService pdfService)
{
_pdfService = pdfService;
}
[HttpPost("html-to-pdf")]
public IActionResult ConvertHtmlToPdf([FromBody] HtmlRequest request)
{
try
{
var pdfBytes = _pdfService.GeneratePdfFromHtml(request.HtmlContent);
// Return as downloadable file
return File(pdfBytes, "application/pdf", "document.pdf");
}
catch (Exception ex)
{
return BadRequest($"Error generating PDF: {ex.Message}");
}
}
}
// Controllers/PdfController.cs
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("api/[controller]")]
public class PdfController : ControllerBase
{
private readonly IPdfService _pdfService;
public PdfController(IPdfService pdfService)
{
_pdfService = pdfService;
}
[HttpPost("html-to-pdf")]
public IActionResult ConvertHtmlToPdf([FromBody] HtmlRequest request)
{
try
{
var pdfBytes = _pdfService.GeneratePdfFromHtml(request.HtmlContent);
// Return as downloadable file
return File(pdfBytes, "application/pdf", "document.pdf");
}
catch (Exception ex)
{
return BadRequest($"Error generating PDF: {ex.Message}");
}
}
}
Imports Microsoft.AspNetCore.Mvc
<ApiController>
<Route("api/[controller]")>
Public Class PdfController
Inherits ControllerBase
Private ReadOnly _pdfService As IPdfService
Public Sub New(pdfService As IPdfService)
_pdfService = pdfService
End Sub
<HttpPost("html-to-pdf")>
Public Function ConvertHtmlToPdf(<FromBody> request As HtmlRequest) As IActionResult
Try
Dim pdfBytes = _pdfService.GeneratePdfFromHtml(request.HtmlContent)
' Return as downloadable file
Return File(pdfBytes, "application/pdf", "document.pdf")
Catch ex As Exception
Return BadRequest($"Error generating PDF: {ex.Message}")
End Try
End Function
End Class
Em seguida, no arquivo HtmlRequest.cs, adicionaremos o seguinte:
// Models/HtmlRequest.cs
public class HtmlRequest
{
public string HtmlContent { get; set; }
public string FileName { get; set; } = "document.pdf";
}
// Models/HtmlRequest.cs
public class HtmlRequest
{
public string HtmlContent { get; set; }
public string FileName { get; set; } = "document.pdf";
}
' Models/HtmlRequest.vb
Public Class HtmlRequest
Public Property HtmlContent As String
Public Property FileName As String = "document.pdf"
End Class
No primeiro arquivo, configuramos um endpoint de API simples que transforma HTML em um PDF para download. Quando alguém envia conteúdo HTML para a rota api/pdf/html-to-pdf com uma simples requisição POST, o PdfController delega a tarefa de convertê-lo em PDF para um serviço dedicado.
Após a criação do PDF, o controlador o devolve ao usuário como um arquivo pronto para download. A própria requisição é estruturada usando o modelo HtmlRequest, que carrega tanto o HTML bruto quanto um nome de arquivo opcional para o documento final. Resumindo, essa configuração facilita para os clientes o envio de HTML e o recebimento instantâneo de um PDF finalizado.
Serviços de Registro
Atualize seu arquivo Program.cs para registrar o serviço de PDF:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
// Register PDF service
builder.Services.AddSingleton<IPdfService, PdfService>();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.MapControllers();
app.Run();
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
// Register PDF service
builder.Services.AddSingleton<IPdfService, PdfService>();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.MapControllers();
app.Run();
Imports Microsoft.AspNetCore.Builder
Imports Microsoft.Extensions.DependencyInjection
Dim builder = WebApplication.CreateBuilder(args)
builder.Services.AddControllers()
builder.Services.AddEndpointsApiExplorer()
builder.Services.AddSwaggerGen()
' Register PDF service
builder.Services.AddSingleton(Of IPdfService, PdfService)()
Dim app = builder.Build()
If app.Environment.IsDevelopment() Then
app.UseSwagger()
app.UseSwaggerUI()
End If
app.UseHttpsRedirection()
app.MapControllers()
app.Run()
Como lidar com diferentes tipos de resposta?
Sua API deve suportar diferentes maneiras de retornar PDFs com base nas necessidades do cliente:
[HttpPost("generate")]
public IActionResult GeneratePdf([FromBody] PdfRequest request)
{
var pdfBytes = _pdfService.GeneratePdfFromHtml(request.HtmlContent);
switch (request.ResponseType?.ToLower())
{
case "base64":
return Ok(new
{
data = Convert.ToBase64String(pdfBytes),
filename = request.FileName
});
case "inline":
return File(pdfBytes, "application/pdf");
default: // download
return File(pdfBytes, "application/pdf", request.FileName);
}
}
[HttpPost("generate")]
public IActionResult GeneratePdf([FromBody] PdfRequest request)
{
var pdfBytes = _pdfService.GeneratePdfFromHtml(request.HtmlContent);
switch (request.ResponseType?.ToLower())
{
case "base64":
return Ok(new
{
data = Convert.ToBase64String(pdfBytes),
filename = request.FileName
});
case "inline":
return File(pdfBytes, "application/pdf");
default: // download
return File(pdfBytes, "application/pdf", request.FileName);
}
}
Imports Microsoft.AspNetCore.Mvc
<HttpPost("generate")>
Public Function GeneratePdf(<FromBody> request As PdfRequest) As IActionResult
Dim pdfBytes = _pdfService.GeneratePdfFromHtml(request.HtmlContent)
Select Case request.ResponseType?.ToLower()
Case "base64"
Return Ok(New With {
.data = Convert.ToBase64String(pdfBytes),
.filename = request.FileName
})
Case "inline"
Return File(pdfBytes, "application/pdf")
Case Else ' download
Return File(pdfBytes, "application/pdf", request.FileName)
End Select
End Function
Aqui, adicionamos um endpoint de geração de PDF mais flexível ao controlador. Em vez de sempre forçar o download de um arquivo, o método GeneratePdf permite que o cliente escolha como deseja que o resultado seja retornado. Essa opção oferece flexibilidade, permitindo que os PDFs sejam exibidos em vários formatos: como um arquivo para download, diretamente no navegador ou codificados como uma string Base64 para facilitar o uso em APIs.
A solicitação é definida pelo modelo PdfRequest, que se baseia no modelo HtmlRequest anterior e adiciona uma opção ResponseType. Resumindo, isso dá aos usuários mais controle sobre como recebem seus PDFs, tornando a API mais versátil e fácil de usar.
Agora, quando executarmos nosso programa, veremos essa saída no Swagger.

Como implementar operações comuns em PDF?
Vamos expandir nosso serviço para lidar com diversos cenários de geração de PDFs:
Conversão de URL para PDF
[HttpPost("url-to-pdf")]
public async Task<IActionResult> ConvertUrlToPdf([FromBody] UrlRequest request)
{
try
{
var pdfBytes = await Task.Run(() =>
_pdfService.GeneratePdfFromUrl(request.Url));
return File(pdfBytes, "application/pdf",
$"{request.FileName ?? "website"}.pdf");
}
catch (Exception ex)
{
return BadRequest($"Failed to convert URL: {ex.Message}");
}
}
public class UrlRequest
{
public string Url { get; set; }
public string FileName { get; set; }
}
[HttpPost("url-to-pdf")]
public async Task<IActionResult> ConvertUrlToPdf([FromBody] UrlRequest request)
{
try
{
var pdfBytes = await Task.Run(() =>
_pdfService.GeneratePdfFromUrl(request.Url));
return File(pdfBytes, "application/pdf",
$"{request.FileName ?? "website"}.pdf");
}
catch (Exception ex)
{
return BadRequest($"Failed to convert URL: {ex.Message}");
}
}
public class UrlRequest
{
public string Url { get; set; }
public string FileName { get; set; }
}
Imports System.Threading.Tasks
Imports Microsoft.AspNetCore.Mvc
<HttpPost("url-to-pdf")>
Public Async Function ConvertUrlToPdf(<FromBody> request As UrlRequest) As Task(Of IActionResult)
Try
Dim pdfBytes = Await Task.Run(Function() _pdfService.GeneratePdfFromUrl(request.Url))
Return File(pdfBytes, "application/pdf", $"{If(request.FileName, "website")}.pdf")
Catch ex As Exception
Return BadRequest($"Failed to convert URL: {ex.Message}")
End Try
End Function
Public Class UrlRequest
Public Property Url As String
Public Property FileName As String
End Class
Este endpoint permite que os clientes enviem um URL e recebam de volta um PDF da página web pronto para download. Quando uma solicitação POST para /api/pdf/url-to-pdf é recebida, o controlador usa o _pdfService para converter a URL fornecida em bytes PDF em segundo plano e, em seguida, os retorna como um arquivo para download. Se algo der errado durante a conversão, o programa responde de forma adequada com uma mensagem de erro clara.
Vamos tentar usar a URL "https://www.apple.com/nz "e teste a solicitação POST. Abaixo está a saída que obtivemos."
Saída

Adicionando marcas d'água personalizadas
public byte[] AddWatermarkFromFile(string filePath, string watermarkText)
{
// Load PDF directly from file
var pdf = PdfDocument.FromFile(filePath);
pdf.ApplyWatermark(
$"<h1 style='color:red;font-size:72px;'>{watermarkText}</h1>",
75,
IronPdf.Editing.VerticalAlignment.Middle,
IronPdf.Editing.HorizontalAlignment.Center
);
return pdf.BinaryData;
}
public byte[] AddWatermarkFromFile(string filePath, string watermarkText)
{
// Load PDF directly from file
var pdf = PdfDocument.FromFile(filePath);
pdf.ApplyWatermark(
$"<h1 style='color:red;font-size:72px;'>{watermarkText}</h1>",
75,
IronPdf.Editing.VerticalAlignment.Middle,
IronPdf.Editing.HorizontalAlignment.Center
);
return pdf.BinaryData;
}
Imports IronPdf
Public Function AddWatermarkFromFile(filePath As String, watermarkText As String) As Byte()
' Load PDF directly from file
Dim pdf = PdfDocument.FromFile(filePath)
pdf.ApplyWatermark(
$"<h1 style='color:red;font-size:72px;'>{watermarkText}</h1>",
75,
IronPdf.Editing.VerticalAlignment.Middle,
IronPdf.Editing.HorizontalAlignment.Center
)
Return pdf.BinaryData
End Function
Aqui, estamos apenas carregando manualmente um arquivo local para fins de teste. No entanto, você pode ajustar isso para que sua API de PDF gere um documento PDF e, em seguida, aplicar uma marca d'água personalizada com facilidade.
Saída de marca d'água

Como adicionar dados dinâmicos com modelos
Para aplicações práticas, você frequentemente precisará gerar PDFs a partir de modelos com dados dinâmicos:
[HttpPost("from-template")]
public IActionResult GenerateFromTemplate([FromBody] TemplateRequest request)
{
// Simple template replacement
var html = request.Template;
foreach (var item in request.Data)
{
html = html.Replace($"{{{{{item.Key}}}}}", item.Value);
}
var pdfBytes = _pdfService.GeneratePdfFromHtml(html);
return File(pdfBytes, "application/pdf", request.FileName);
}
public class TemplateRequest
{
public string Template { get; set; }
public Dictionary<string, string> Data { get; set; }
public string FileName { get; set; } = "document.pdf";
}
[HttpPost("from-template")]
public IActionResult GenerateFromTemplate([FromBody] TemplateRequest request)
{
// Simple template replacement
var html = request.Template;
foreach (var item in request.Data)
{
html = html.Replace($"{{{{{item.Key}}}}}", item.Value);
}
var pdfBytes = _pdfService.GeneratePdfFromHtml(html);
return File(pdfBytes, "application/pdf", request.FileName);
}
public class TemplateRequest
{
public string Template { get; set; }
public Dictionary<string, string> Data { get; set; }
public string FileName { get; set; } = "document.pdf";
}
Imports Microsoft.AspNetCore.Mvc
<HttpPost("from-template")>
Public Function GenerateFromTemplate(<FromBody> request As TemplateRequest) As IActionResult
' Simple template replacement
Dim html As String = request.Template
For Each item In request.Data
html = html.Replace($"{{{{{item.Key}}}}}", item.Value)
Next
Dim pdfBytes As Byte() = _pdfService.GeneratePdfFromHtml(html)
Return File(pdfBytes, "application/pdf", request.FileName)
End Function
Public Class TemplateRequest
Public Property Template As String
Public Property Data As Dictionary(Of String, String)
Public Property FileName As String = "document.pdf"
End Class
Para cenários de modelos mais avançados com Razor, Handlebars ou outros mecanismos, consulte a documentação de HTML para PDF do IronPDF . Você também pode explorar a conversão de CSHTML para PDF para aplicativos MVC e de Razor para PDF para aplicativos Blazor .
Como otimizar o desempenho?
Ao construir uma API de PDF para produção, o desempenho é crucial. Aqui estão as principais estratégias de otimização:
Operações assíncronas
Ao desenvolver projetos que envolvam o uso de operações de entrada/saída, é aconselhável utilizar programação assíncrona. Isso é especialmente útil se o conteúdo do seu PDF vier de fontes externas, como:
- Baixando páginas HTML (RenderUrlAsPdf)
- Obtenção de imagens, CSS ou fontes via HTTP
- Leitura/gravação de arquivos em disco ou armazenamento em nuvem
Essas operações podem bloquear uma thread, mas o uso de async impede que a thread da sua API fique ociosa.
Exemplo:
public async Task<byte[]> GeneratePdfFromHtmlAsync(string htmlContent)
{
return await Task.Run(() =>
{
var pdf = _renderer.RenderHtmlAsPdf(htmlContent);
return pdf.BinaryData;
});
}
public async Task<byte[]> GeneratePdfFromHtmlAsync(string htmlContent)
{
return await Task.Run(() =>
{
var pdf = _renderer.RenderHtmlAsPdf(htmlContent);
return pdf.BinaryData;
});
}
Imports System.Threading.Tasks
Public Async Function GeneratePdfFromHtmlAsync(htmlContent As String) As Task(Of Byte())
Return Await Task.Run(Function()
Dim pdf = _renderer.RenderHtmlAsPdf(htmlContent)
Return pdf.BinaryData
End Function)
End Function
Opções de renderização
Configure o IronPDF para obter o melhor desempenho:
_renderer.RenderingOptions.EnableJavaScript = false; // If JS not needed
_renderer.RenderingOptions.CssMediaType = PdfCssMediaType.Print;
_renderer.RenderingOptions.RenderDelay = 0; // Remove if no JS
_renderer.RenderingOptions.Timeout = 30; // Set reasonable timeout
_renderer.RenderingOptions.EnableJavaScript = false; // If JS not needed
_renderer.RenderingOptions.CssMediaType = PdfCssMediaType.Print;
_renderer.RenderingOptions.RenderDelay = 0; // Remove if no JS
_renderer.RenderingOptions.Timeout = 30; // Set reasonable timeout
Como proteger sua API de PDF?
A segurança é essencial para qualquer API de produção. Aqui está uma abordagem simples para autenticação por chave de API:
// Middleware/ApiKeyMiddleware.cs
public class ApiKeyMiddleware
{
private readonly RequestDelegate _next;
private const string ApiKeyHeader = "X-API-Key";
public ApiKeyMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
if (!context.Request.Headers.TryGetValue(ApiKeyHeader, out var apiKey))
{
context.Response.StatusCode = 401;
await context.Response.WriteAsync("API Key required");
return;
}
// Validate API key (in production, check against database)
var validApiKey = context.RequestServices
.GetRequiredService<IConfiguration>()["ApiKey"];
if (apiKey != validApiKey)
{
context.Response.StatusCode = 403;
await context.Response.WriteAsync("Invalid API Key");
return;
}
await _next(context);
}
}
// In Program.cs
app.UseMiddleware<ApiKeyMiddleware>();
// Middleware/ApiKeyMiddleware.cs
public class ApiKeyMiddleware
{
private readonly RequestDelegate _next;
private const string ApiKeyHeader = "X-API-Key";
public ApiKeyMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
if (!context.Request.Headers.TryGetValue(ApiKeyHeader, out var apiKey))
{
context.Response.StatusCode = 401;
await context.Response.WriteAsync("API Key required");
return;
}
// Validate API key (in production, check against database)
var validApiKey = context.RequestServices
.GetRequiredService<IConfiguration>()["ApiKey"];
if (apiKey != validApiKey)
{
context.Response.StatusCode = 403;
await context.Response.WriteAsync("Invalid API Key");
return;
}
await _next(context);
}
}
// In Program.cs
app.UseMiddleware<ApiKeyMiddleware>();
Imports Microsoft.AspNetCore.Http
Imports Microsoft.Extensions.Configuration
Imports System.Threading.Tasks
' Middleware/ApiKeyMiddleware.vb
Public Class ApiKeyMiddleware
Private ReadOnly _next As RequestDelegate
Private Const ApiKeyHeader As String = "X-API-Key"
Public Sub New(next As RequestDelegate)
_next = next
End Sub
Public Async Function InvokeAsync(context As HttpContext) As Task
Dim apiKey As String = Nothing
If Not context.Request.Headers.TryGetValue(ApiKeyHeader, apiKey) Then
context.Response.StatusCode = 401
Await context.Response.WriteAsync("API Key required")
Return
End If
' Validate API key (in production, check against database)
Dim validApiKey As String = context.RequestServices.GetRequiredService(Of IConfiguration)()("ApiKey")
If apiKey <> validApiKey Then
context.Response.StatusCode = 403
Await context.Response.WriteAsync("Invalid API Key")
Return
End If
Await _next(context)
End Function
End Class
' In Program.vb
app.UseMiddleware(Of ApiKeyMiddleware)()
Para cenários de autenticação mais avançados, considere:
- Autenticação JWT - Padrão da indústria para autenticação de API
- OAuth 2.0 - Para integrações de terceiros
- Integração com o Azure AD - Autenticação empresarial
- Limitação de taxa de API - Previna abusos e assegure o uso justo.
Exemplo prático: API de geração de faturas
Vamos construir um endpoint prático para geração de faturas que demonstre uma implementação completa. Este exemplo mostra como uma API .NET PDF de produção pode gerar faturas profissionais com dados dinâmicos.
Comece a usar IronPDF no seu projeto hoje mesmo com um teste gratuito.
Primeiro, vamos criar um novo arquivo na nossa pasta Modelos. Aqui, eu dei o nome de Invoice.cs ao meu arquivo. Em seguida, adicione o seguinte código ao seu novo arquivo.
public class Invoice
{
public string InvoiceNumber { get; set; }
public DateTime Date { get; set; }
public string CustomerName { get; set; }
public string CustomerAddress { get; set; }
public List<InvoiceItem> Items { get; set; }
public decimal Tax { get; set; }
}
public class InvoiceItem
{
public string Description { get; set; }
public int Quantity { get; set; }
public decimal UnitPrice { get; set; }
public decimal Total => Quantity * UnitPrice;
}
public class Invoice
{
public string InvoiceNumber { get; set; }
public DateTime Date { get; set; }
public string CustomerName { get; set; }
public string CustomerAddress { get; set; }
public List<InvoiceItem> Items { get; set; }
public decimal Tax { get; set; }
}
public class InvoiceItem
{
public string Description { get; set; }
public int Quantity { get; set; }
public decimal UnitPrice { get; set; }
public decimal Total => Quantity * UnitPrice;
}
Public Class Invoice
Public Property InvoiceNumber As String
Public Property [Date] As DateTime
Public Property CustomerName As String
Public Property CustomerAddress As String
Public Property Items As List(Of InvoiceItem)
Public Property Tax As Decimal
End Class
Public Class InvoiceItem
Public Property Description As String
Public Property Quantity As Integer
Public Property UnitPrice As Decimal
Public ReadOnly Property Total As Decimal
Get
Return Quantity * UnitPrice
End Get
End Property
End Class
Em seguida, precisaremos criar um novo arquivo de serviço para o nosso gerador de faturas. Na sua pasta Serviços, adicione o seguinte código. No meu caso, criei um novo arquivo chamado InvoiceService.cs. Este código irá gerenciar o estilo e o layout do nosso arquivo PDF de fatura.
public class InvoiceService
{
private readonly ChromePdfRenderer _renderer;
public InvoiceService()
{
_renderer = new ChromePdfRenderer();
_renderer.RenderingOptions.MarginTop = 10;
_renderer.RenderingOptions.MarginBottom = 10;
_renderer.RenderingOptions.PrintHtmlBackgrounds = true;
}
public byte[] GenerateInvoice(Invoice invoice)
{
var html = BuildInvoiceHtml(invoice);
// Add footer with page numbers
_renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
MaxHeight = 15,
HtmlFragment = "<center><i>{page} of {total-pages}</i></center>",
DrawDividerLine = true
};
var pdf = _renderer.RenderHtmlAsPdf(html);
return pdf.BinaryData;
}
private string BuildInvoiceHtml(Invoice invoice)
{
var subtotal = invoice.Items.Sum(i => i.Total);
var taxAmount = subtotal * (invoice.Tax / 100);
var total = subtotal + taxAmount;
var itemsHtml = string.Join("", invoice.Items.Select(item =>
$@"<tr>
<td>{item.Description}</td>
<td class='text-center'>{item.Quantity}</td>
<td class='text-right'>${item.UnitPrice:F2}</td>
<td class='text-right'>${item.Total:F2}</td>
</tr>"));
return $@"
<!DOCTYPE html>
<html>
<head>
<style>
body {{ font-family: Arial, sans-serif; }}
.invoice-header {{
background-color: #f8f9fa;
padding: 20px;
margin-bottom: 20px;
}}
table {{
width: 100%;
border-collapse: collapse;
}}
th, td {{
padding: 10px;
border-bottom: 1px solid #ddd;
}}
th {{
background-color: #007bff;
color: white;
}}
.text-right {{ text-align: right; }}
.text-center {{ text-align: center; }}
.total-section {{
margin-top: 20px;
text-align: right;
}}
</style>
</head>
<body>
<div class='invoice-header'>
<h1>Invoice #{invoice.InvoiceNumber}</h1>
<p>Date: {invoice.Date:yyyy-MM-dd}</p>
</div>
<div>
<h3>Bill To:</h3>
<p>{invoice.CustomerName}<br/>{invoice.CustomerAddress}</p>
</div>
<table>
<thead>
<tr>
<th>Description</th>
<th>Quantity</th>
<th>Unit Price</th>
<th>Total</th>
</tr>
</thead>
<tbody>
{itemsHtml}
</tbody>
</table>
<div class='total-section'>
<p>Subtotal: ${subtotal:F2}</p>
<p>Tax ({invoice.Tax}%): ${taxAmount:F2}</p>
<h3>Total: ${total:F2}</h3>
</div>
</body>
</html>";
}
}
public class InvoiceService
{
private readonly ChromePdfRenderer _renderer;
public InvoiceService()
{
_renderer = new ChromePdfRenderer();
_renderer.RenderingOptions.MarginTop = 10;
_renderer.RenderingOptions.MarginBottom = 10;
_renderer.RenderingOptions.PrintHtmlBackgrounds = true;
}
public byte[] GenerateInvoice(Invoice invoice)
{
var html = BuildInvoiceHtml(invoice);
// Add footer with page numbers
_renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
MaxHeight = 15,
HtmlFragment = "<center><i>{page} of {total-pages}</i></center>",
DrawDividerLine = true
};
var pdf = _renderer.RenderHtmlAsPdf(html);
return pdf.BinaryData;
}
private string BuildInvoiceHtml(Invoice invoice)
{
var subtotal = invoice.Items.Sum(i => i.Total);
var taxAmount = subtotal * (invoice.Tax / 100);
var total = subtotal + taxAmount;
var itemsHtml = string.Join("", invoice.Items.Select(item =>
$@"<tr>
<td>{item.Description}</td>
<td class='text-center'>{item.Quantity}</td>
<td class='text-right'>${item.UnitPrice:F2}</td>
<td class='text-right'>${item.Total:F2}</td>
</tr>"));
return $@"
<!DOCTYPE html>
<html>
<head>
<style>
body {{ font-family: Arial, sans-serif; }}
.invoice-header {{
background-color: #f8f9fa;
padding: 20px;
margin-bottom: 20px;
}}
table {{
width: 100%;
border-collapse: collapse;
}}
th, td {{
padding: 10px;
border-bottom: 1px solid #ddd;
}}
th {{
background-color: #007bff;
color: white;
}}
.text-right {{ text-align: right; }}
.text-center {{ text-align: center; }}
.total-section {{
margin-top: 20px;
text-align: right;
}}
</style>
</head>
<body>
<div class='invoice-header'>
<h1>Invoice #{invoice.InvoiceNumber}</h1>
<p>Date: {invoice.Date:yyyy-MM-dd}</p>
</div>
<div>
<h3>Bill To:</h3>
<p>{invoice.CustomerName}<br/>{invoice.CustomerAddress}</p>
</div>
<table>
<thead>
<tr>
<th>Description</th>
<th>Quantity</th>
<th>Unit Price</th>
<th>Total</th>
</tr>
</thead>
<tbody>
{itemsHtml}
</tbody>
</table>
<div class='total-section'>
<p>Subtotal: ${subtotal:F2}</p>
<p>Tax ({invoice.Tax}%): ${taxAmount:F2}</p>
<h3>Total: ${total:F2}</h3>
</div>
</body>
</html>";
}
}
Imports System
Imports System.Linq
Public Class InvoiceService
Private ReadOnly _renderer As ChromePdfRenderer
Public Sub New()
_renderer = New ChromePdfRenderer()
_renderer.RenderingOptions.MarginTop = 10
_renderer.RenderingOptions.MarginBottom = 10
_renderer.RenderingOptions.PrintHtmlBackgrounds = True
End Sub
Public Function GenerateInvoice(invoice As Invoice) As Byte()
Dim html = BuildInvoiceHtml(invoice)
' Add footer with page numbers
_renderer.RenderingOptions.HtmlFooter = New HtmlHeaderFooter With {
.MaxHeight = 15,
.HtmlFragment = "<center><i>{page} of {total-pages}</i></center>",
.DrawDividerLine = True
}
Dim pdf = _renderer.RenderHtmlAsPdf(html)
Return pdf.BinaryData
End Function
Private Function BuildInvoiceHtml(invoice As Invoice) As String
Dim subtotal = invoice.Items.Sum(Function(i) i.Total)
Dim taxAmount = subtotal * (invoice.Tax / 100)
Dim total = subtotal + taxAmount
Dim itemsHtml = String.Join("", invoice.Items.Select(Function(item)
$"<tr>
<td>{item.Description}</td>
<td class='text-center'>{item.Quantity}</td>
<td class='text-right'>${item.UnitPrice:F2}</td>
<td class='text-right'>${item.Total:F2}</td>
</tr>"))
Return $"
<!DOCTYPE html>
<html>
<head>
<style>
body {{ font-family: Arial, sans-serif; }}
.invoice-header {{
background-color: #f8f9fa;
padding: 20px;
margin-bottom: 20px;
}}
table {{
width: 100%;
border-collapse: collapse;
}}
th, td {{
padding: 10px;
border-bottom: 1px solid #ddd;
}}
th {{
background-color: #007bff;
color: white;
}}
.text-right {{ text-align: right; }}
.text-center {{ text-align: center; }}
.total-section {{
margin-top: 20px;
text-align: right;
}}
</style>
</head>
<body>
<div class='invoice-header'>
<h1>Invoice #{invoice.InvoiceNumber}</h1>
<p>Date: {invoice.Date:yyyy-MM-dd}</p>
</div>
<div>
<h3>Bill To:</h3>
<p>{invoice.CustomerName}<br/>{invoice.CustomerAddress}</p>
</div>
<table>
<thead>
<tr>
<th>Description</th>
<th>Quantity</th>
<th>Unit Price</th>
<th>Total</th>
</tr>
</thead>
<tbody>
{itemsHtml}
</tbody>
</table>
<div class='total-section'>
<p>Subtotal: ${subtotal:F2}</p>
<p>Tax ({invoice.Tax}%): ${taxAmount:F2}</p>
<h3>Total: ${total:F2}</h3>
</div>
</body>
</html>"
End Function
End Class
Por fim, você precisará criar um novo Controlador para acessar e criar uma nova Fatura usando a API.
[ApiController]
[Route("api/[controller]")]
public class InvoiceController : ControllerBase
{
private readonly InvoiceService _invoiceService;
public InvoiceController(InvoiceService invoiceService)
{
_invoiceService = invoiceService;
}
[HttpPost("generate")]
public IActionResult GenerateInvoice([FromBody] Invoice invoice)
{
try
{
var pdfBytes = _invoiceService.GenerateInvoice(invoice);
var fileName = $"Invoice_{invoice.InvoiceNumber}.pdf";
return File(pdfBytes, "application/pdf", fileName);
}
catch (Exception ex)
{
return StatusCode(500, $"Error generating invoice: {ex.Message}");
}
}
}
[ApiController]
[Route("api/[controller]")]
public class InvoiceController : ControllerBase
{
private readonly InvoiceService _invoiceService;
public InvoiceController(InvoiceService invoiceService)
{
_invoiceService = invoiceService;
}
[HttpPost("generate")]
public IActionResult GenerateInvoice([FromBody] Invoice invoice)
{
try
{
var pdfBytes = _invoiceService.GenerateInvoice(invoice);
var fileName = $"Invoice_{invoice.InvoiceNumber}.pdf";
return File(pdfBytes, "application/pdf", fileName);
}
catch (Exception ex)
{
return StatusCode(500, $"Error generating invoice: {ex.Message}");
}
}
}
Imports Microsoft.AspNetCore.Mvc
<ApiController>
<Route("api/[controller]")>
Public Class InvoiceController
Inherits ControllerBase
Private ReadOnly _invoiceService As InvoiceService
Public Sub New(invoiceService As InvoiceService)
_invoiceService = invoiceService
End Sub
<HttpPost("generate")>
Public Function GenerateInvoice(<FromBody> invoice As Invoice) As IActionResult
Try
Dim pdfBytes = _invoiceService.GenerateInvoice(invoice)
Dim fileName = $"Invoice_{invoice.InvoiceNumber}.pdf"
Return File(pdfBytes, "application/pdf", fileName)
Catch ex As Exception
Return StatusCode(500, $"Error generating invoice: {ex.Message}")
End Try
End Function
End Class
Saída de fatura

Considerações sobre a implantação de contêineres
Embora este tutorial se concentre no desenvolvimento local, aqui está uma breve visão geral da conteinerização da sua API de PDF:
Dockerfile básico
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["PdfApiService.csproj", "."]
RUN dotnet restore
COPY . .
RUN dotnet build -c Release -o /app/build
FROM build AS publish
RUN dotnet publish -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
# IronPDF requires additional dependencies on Linux
RUN apt-get update && apt-get install -y \
libgdiplus \
libc6-dev \
libx11-dev \
&& rm -rf /var/lib/apt/lists/*
ENTRYPOINT ["dotnet", "PdfApiService.dll"]
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["PdfApiService.csproj", "."]
RUN dotnet restore
COPY . .
RUN dotnet build -c Release -o /app/build
FROM build AS publish
RUN dotnet publish -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
# IronPDF requires additional dependencies on Linux
RUN apt-get update && apt-get install -y \
libgdiplus \
libc6-dev \
libx11-dev \
&& rm -rf /var/lib/apt/lists/*
ENTRYPOINT ["dotnet", "PdfApiService.dll"]
The provided code is a Dockerfile written for building and running a .NET application, not C# code. Dockerfiles are not converted to VB.NET as they are not programming language code but configuration scripts for Docker. If you have C# code that needs conversion to VB.NET, please provide that code instead.
Para obter guias de implantação detalhados para sua API .NET PDF, consulte:
- Documentação do IronPDF para Docker - Guia completo de conteinerização
- Implantação do IronPDF no Azure - Azure Functions e Serviço de Aplicativos
- Implantação do IronPDF na AWS - Implantação do Lambda e do EC2
- Configuração do IronPDF para Linux - Configuração específica para Linux
Melhores práticas para tratamento de erros
Para um programa mais tolerante a falhas, as melhores práticas consistem em implementar um manipulador de erros global para respostas de erro consistentes, como as abaixo:
// Middleware/ErrorHandlingMiddleware.cs
public class ErrorHandlingMiddleware
{
private readonly RequestDelegate _next;
public ErrorHandlingMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception ex)
{
await HandleExceptionAsync(context, ex);
}
}
private static async Task HandleExceptionAsync(HttpContext context, Exception ex)
{
context.Response.ContentType = "application/json";
context.Response.StatusCode = 500;
var response = new
{
error = "An error occurred processing your request",
message = ex.Message
};
await context.Response.WriteAsync(JsonSerializer.Serialize(response));
}
}
// Middleware/ErrorHandlingMiddleware.cs
public class ErrorHandlingMiddleware
{
private readonly RequestDelegate _next;
public ErrorHandlingMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception ex)
{
await HandleExceptionAsync(context, ex);
}
}
private static async Task HandleExceptionAsync(HttpContext context, Exception ex)
{
context.Response.ContentType = "application/json";
context.Response.StatusCode = 500;
var response = new
{
error = "An error occurred processing your request",
message = ex.Message
};
await context.Response.WriteAsync(JsonSerializer.Serialize(response));
}
}
Imports System.Text.Json
Imports Microsoft.AspNetCore.Http
Imports System.Threading.Tasks
Public Class ErrorHandlingMiddleware
Private ReadOnly _next As RequestDelegate
Public Sub New(next As RequestDelegate)
_next = next
End Sub
Public Async Function InvokeAsync(context As HttpContext) As Task
Try
Await _next(context)
Catch ex As Exception
Await HandleExceptionAsync(context, ex)
End Try
End Function
Private Shared Async Function HandleExceptionAsync(context As HttpContext, ex As Exception) As Task
context.Response.ContentType = "application/json"
context.Response.StatusCode = 500
Dim response = New With {
.error = "An error occurred processing your request",
.message = ex.Message
}
Await context.Response.WriteAsync(JsonSerializer.Serialize(response))
End Function
End Class
Para cenários específicos de resolução de problemas do IronPDF , consulte o guia de resolução de problemas do IronPDF .
Conclusão
Você acabou de criar uma API .NET PDF robusta usando ASP.NET Core e IronPDF , capaz de lidar com diversos cenários de geração de documentos. Esta API REST fornece uma base sólida para operações centralizadas de PDF em seus aplicativos.
Principais conclusões:
- O IronPDF simplifica a geração de PDFs em projetos de API Web com sua renderização baseada no Chrome.
- Você pode facilmente ajustar sua API Web para editar documentos PDF existentes com as ferramentas avançadas de edição do IronPDF.
- Os princípios de design RESTful garantem que sua API de PDF seja intuitiva e de fácil manutenção.
- O tratamento adequado de erros e as medidas de segurança são essenciais para a produção.
- A otimização de desempenho por meio de operações assíncronas e cache melhora a escalabilidade. Você terá suporte para aplicativos de desktop e web com soluções de documentos escaláveis.
O IronPDF permite que os desenvolvedores criem documentos PDF, salvem arquivos PDF e convertam HTML de forma eficiente, tornando-se a API de documentos PDF essencial para aplicativos modernos do .NET Framework .
Próximos passos
Pronto para implementar o IronPDF em sua API de PDF .NET de produção? Eis as suas próximas ações:
- Inicie seu teste gratuito - Teste o IronPDF com todas as funcionalidades em seu ambiente de desenvolvimento.
- Explore recursos avançados - Confira assinaturas digitais , formulários em PDF e outros recursos avançados de PDF.
- Expanda com confiança - Analise as opções de licenciamento para as suas necessidades de API de produção.
Crie sua API de PDF for .NET hoje mesmo e simplifique a geração de documentos em todo o seu ecossistema de aplicativos com o IronPDF!
Perguntas frequentes
O que é uma API PDF for .NET?
Uma API .NET para PDF é uma biblioteca que permite aos desenvolvedores criar, editar e extrair conteúdo de PDFs em aplicações .NET. Ela simplifica tarefas complexas com PDFs e garante o gerenciamento eficiente desses arquivos.
Como uma API de PDF for .NET pode beneficiar minha aplicação?
Uma API .NET para PDF pode aprimorar seu aplicativo, fornecendo consistência, facilidade de manutenção e escalabilidade no gerenciamento de arquivos PDF, como a geração de faturas, relatórios, certificados ou contratos.
Quais são alguns casos de uso comuns para uma API de PDF em .NET?
Os casos de uso comuns para uma API .NET PDF incluem a geração de faturas, a criação de relatórios, a emissão de certificados e o gerenciamento de contratos em aplicativos desktop e web.
Como o IronPDF simplifica as tarefas de geração de PDFs?
O IronPDF simplifica as tarefas de geração de PDFs, oferecendo uma biblioteca robusta que permite o gerenciamento fácil do conteúdo do documento, das páginas do PDF e dos campos do formulário, facilitando a manutenção e a escalabilidade das aplicações.
O IronPDF consegue lidar com campos de formulário em PDF?
Sim, o IronPDF consegue gerenciar campos de formulários PDF de forma eficiente, permitindo que desenvolvedores criem, preencham e extraiam dados de formulários dentro de documentos PDF.
O IronPDF é adequado tanto para aplicações desktop quanto para aplicações web?
Sem dúvida, o IronPDF foi projetado para funcionar perfeitamente tanto em aplicativos desktop quanto na web, oferecendo uma solução consistente e escalável para gerenciamento de PDFs.
O que torna o IronPDF uma escolha confiável para desenvolvedores .NET?
O IronPDF é uma escolha confiável para desenvolvedores .NET devido à sua facilidade de uso, recursos abrangentes e capacidade de otimizar tarefas com PDFs, o que aumenta a produtividade e o desempenho do aplicativo.
O IronPDF oferece suporte a recursos de extração de PDF?
Sim, o IronPDF oferece suporte a recursos de extração de PDF, permitindo extrair texto, imagens e outros dados de documentos PDF de forma eficiente.
Como o IronPDF melhora a escalabilidade no gerenciamento de PDFs?
O IronPDF melhora a escalabilidade ao fornecer um serviço centralizado de geração de PDFs que consegue lidar com demandas crescentes sem sacrificar o desempenho, tornando-o ideal para aplicações em expansão.
Que tipo de suporte o IronPDF oferece para aplicações .NET?
O IronPDF oferece amplo suporte para aplicativos .NET, incluindo documentação detalhada, código de exemplo e uma equipe de suporte ágil para auxiliar os desenvolvedores na integração de funcionalidades de PDF.
O IronPDF é totalmente compatível com o .NET 10?
Sim — o IronPDF é totalmente compatível com o .NET 10. Ele suporta todos os aprimoramentos de desempenho, linguagem e tempo de execução introduzidos pelo .NET 10 e funciona imediatamente em projetos .NET 10, assim como funcionava com versões anteriores, como .NET 6, 7, 8 e 9.


