跳至页脚内容
使用IRONPDF

如何使用IronPDF创建.NET PDF API

在使用现代应用程序时,像您这样的.NET开发人员可能会发现需要构建一个集中的PDF生成服务。无论您是生成发票、报告、证书或合同,拥有一个专门的.NET PDF API对于高效管理PDF文件都是有益的。 那么它如何改善您的PDF生成任务呢? 它通过在桌面和Web应用程序之间提供一致性、可维护性和可扩展性来实现这一点。 从未有过如此轻松地管理文档内容、PDF页面和PDF表单字段。

在本教程中,您将学习如何使用ASP.NET Core和IronPDF,一个强大的.NET PDF库,构建一个可用于生产的PDF API。 我们将创建可以从HTML生成PDF、合并文档、添加水印并处理Web API中各种实际PDF生成场景的RESTful端点。

为什么构建一个专门的PDF API?

在深入研究代码之前,让我们了解为什么创建一个专门的PDF API是有意义的:

  • 集中化逻辑:所有的PDF生成逻辑都集中在一个地方,使得维护和更新更加容易
  • 微服务架构:对于需要PDF功能的不同应用程序的面向服务架构来说是完美的
  • 性能优化:更容易为大型PDF文件、多页面和动态数据优化和扩展专用服务。
  • 语言无关:任何客户端应用程序都可以消费该API,无论编程语言如何
  • 输出一致性:确保整个组织的所有PDF文档都保持一致的文档布局、段落格式和PDF内容。

准备好开始构建了吗? 下载IronPDF的免费试用版,并按此教程一起编程实现.NET Framework项目中的PDF文件创建。

IronPDF: 完整的.NET PDF库

IronPDF被认为是.NET开发人员的首选PDF库,提供了一套全面的功能,使Web API项目中的PDF生成过程简单可靠。 它建立在Chrome渲染引擎上,确保像素级精准的HTML到PDF转换,通常只需几行代码即可完成。 这在保持所有样式、JavaScript执行和响应布局的同时完成。

使IronPDF成为.NET PDF API开发的理想选择的关键能力有:

  • 基于Chrome的渲染:利用Google Chrome的渲染引擎准确地将HTML内容转换为PDF文档,完全支持嵌入图像和其他Web资产
  • Rich Feature Set: Supports the editing of new and existing documents with digital signatures, PDF forms, annotations, encryption, compression, and more
  • 创建安全的PDF文档: 使用加密、数字签名和文档保护来管理敏感的PDF内容。
  • Multiple Input Formats: Use HTML, URLs, images, and Office documents to create PDF documents
  • 高级操作:合并PDF页面、拆分文档、应用水印、创建互动PDF表单,并以编程方式操作PDF文件。
  • Cross-Platform Support: Works on Windows, Linux, macOS, Docker, and cloud platforms
  • 性能优化异步操作、高效的内存管理和快速渲染

如何设置您的PDF文档API项目?

让我们从创建一个新的ASP.NET Core Web API项目并安装必要的包开始。

前提条件

  • .NET 6.0 SDK或更高版本
  • Visual Studio 2022或Visual Studio Code
  • Postman或类似的API测试工具,以测试您的PDF REST API

创建项目

首先,让我们创建一个项目,我们将在其中构建我们的PDF生成工具。

dotnet new webapi -n PdfApiService
cd PdfApiService

安装 IronPDF。

下一步是通过NuGet将IronPDF添加到您的项目中:

dotnet add package IronPdf

或者,在Visual Studio中使用NuGet包管理器控制台:

Install-Package IronPdf

项目结构

C#开发的一个重要方面是保持一个干净且结构良好的项目文件夹。 例如:

如何创建您的第一个PDF端点?

让我们构建一个简单的端点,将HTML转换为PDF格式。 首先,创建服务接口和实现:

创建PDF服务

首先,我们将在我们的IPdfService.cs文件中添加以下内容:

public interface IPdfService
{
    byte[] GeneratePdfFromHtml(string htmlContent);
    byte[] GeneratePdfFromUrl(string url);
}
public interface IPdfService
{
    byte[] GeneratePdfFromHtml(string htmlContent);
    byte[] GeneratePdfFromUrl(string url);
}
IRON VB CONVERTER ERROR developers@ironsoftware.com
$vbLabelText   $csharpLabel

在PdfService.cs文件中,我们将添加:

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;
    }
}
IRON VB CONVERTER ERROR developers@ironsoftware.com
$vbLabelText   $csharpLabel

PdfService处理将HTML转换为PDF的核心过程。 利用IronPDF的ChromePdfRenderer,此类设置了合理的默认值,如页面边距和背景渲染,以生成一个精美的最终文档。

当控制器传递原始HTML时,服务使用IronPDF将其呈现为专业质量的PDF,并将结果返回为字节数据,准备好下载。 此外,它还可以通过将URL直接转换为PDF来处理整个网页。

创建控制器

现在是为我们的API创建控制器的时间了。 这将提供一个可以从HTML生成PDF文件的API端点。 然后,能够下载并将PDF文档保存到您的系统中,以便进一步使用或共享。

// 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}");
        }
    }
}
IRON VB CONVERTER ERROR developers@ironsoftware.com
$vbLabelText   $csharpLabel

然后,在HtmlRequest.cs文件中,我们将添加:

// 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";
}
IRON VB CONVERTER ERROR developers@ironsoftware.com
$vbLabelText   $csharpLabel

在第一个文件中,我们设置了一个简单的API端点,将HTML转换为可下载的PDF。 当有人通过简单的POST请求将HTML内容发送到api/pdf/html-to-pdf路由时,PdfController将任务传递给专用的服务,将其转换为PDF。

一旦PDF创建完成,控制器将它作为一个准备好下载的文件返回给用户。请求本身是使用HtmlRequest模型结构化的,该模型携带原始HTML和用于最终文档的可选文件名。 简而言之,此设置使得客户端可以轻松发送HTML并立即获得一个精美的PDF作为返回。

注册服务

更新您的Program.cs以注册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();
IRON VB CONVERTER ERROR developers@ironsoftware.com
$vbLabelText   $csharpLabel

如何处理不同的响应类型?

您的API应该支持基于客户端需求以不同方式返回PDF:

[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);
     }
 }
IRON VB CONVERTER ERROR developers@ironsoftware.com
$vbLabelText   $csharpLabel

在这里,我们在控制器中添加了一个更灵活的PDF生成端点。 而不是总是强制下载文件,GeneratePdf方法让客户端选择他们希望结果如何返回。 此选项提供灵活性,允许PDF以多种格式显示:作为可下载文件,直接在浏览器中,或编码为Base64字符串以便在API中轻松使用。

请求由PdfRequest模型定义,该模型基于之前的HtmlRequest,并添加一个ResponseType选项。 总之,这使用户能够更好地控制如何接收他们的PDF,使API更加多样化和用户友好。

现在,当我们运行程序时,我们将在Swagger上看到此输出。

如何使用IronPDF创建.NET PDF API:图4 - Swagger UI

如何实现常见的PDF操作?

让我们扩展我们的服务以处理各种PDF生成场景:

URL到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; }
}
IRON VB CONVERTER ERROR developers@ironsoftware.com
$vbLabelText   $csharpLabel

此端点允许客户端发送一个URL并获取该网页的可下载PDF。 当POST /api/pdf/url-to-pdf请求到达时,控制器使用_pdfService后台将给定的URL转换为PDF字节,然后以文件下载的形式返回。 如果在转换过程中出现问题,它会优雅地响应一个清晰的错误信息。

让我们尝试使用网址“https://www.apple.com/nz”并测试POST请求。下面是我们获得的输出。

输出

如何使用IronPDF创建.NET PDF API:图5 - URL PDF输出

添加自定义水印

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;
}
IRON VB CONVERTER ERROR developers@ironsoftware.com
$vbLabelText   $csharpLabel

在这里,我们只是手动加载一个本地的文件以进行测试。 然而,您可以调整这个,以便您的PDF API生成PDF文档,然后轻松地应用自定义水印。

水印输出

如何使用IronPDF创建.NET PDF API:图6 - 上述代码示例中的水印输出

如何使用模板添加动态数据

对于真实世界的应用程序,您通常需要从模板生成带有动态数据的PDFs:

[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";
}
IRON VB CONVERTER ERROR developers@ironsoftware.com
$vbLabelText   $csharpLabel

对于更高级的模板场景,请查看IronPDF的HTML到PDF文档。 You can also explore CSHTML to PDF conversion for MVC applications and Razor to PDF for Blazor applications.

如何优化性能?

在构建生产PDF API时,性能至关重要。 以下是关键的优化策略:

异步操作

当构建涉及使用I/O操作的项目时,明智的做法是使用异步编码。 如果您的PDF内容来自外部资源,这尤其有用,例如:

  • 下载HTML页面(RenderUrlAsPdf)
  • 通过HTTP获取图像、CSS或字体
  • 读取/写入磁盘或云存储的文件

这些操作可以阻塞线程,但使用异步可以防止您的API线程空闲等待。

例:

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;
    });
}
IRON VB CONVERTER ERROR developers@ironsoftware.com
$vbLabelText   $csharpLabel

渲染选项

配置IronPDF以获得最佳性能:

_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
IRON VB CONVERTER ERROR developers@ironsoftware.com
$vbLabelText   $csharpLabel

如何保护您的PDF API?

对于任何生产API,安全性都是至关重要的。 这里是一个简单的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>();
IRON VB CONVERTER ERROR developers@ironsoftware.com
$vbLabelText   $csharpLabel

对于更高级的身份验证场景,请考虑:

Real-World 例: Invoice Generation API

让我们构建一个实际的发票生成端点,演示完整的实现。 此示例展示了如何使用生产.NET PDF API生成具有动态数据的专业发票。

立即开始使用 IronPDF。
green arrow pointer

首先,我们将在我们的Models文件夹中创建一个新文件。 在这里,我将其称之为Invoice.cs。 然后,将以下代码添加到您的新文件中。

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;
}
IRON VB CONVERTER ERROR developers@ironsoftware.com
$vbLabelText   $csharpLabel

然后,我们将需要为我们的发票生成器创建一个新的服务文件。 在您的Services文件夹中,添加以下代码。 对于我的,我创建了一个名为InvoiceService.cs的新文件。 这段代码将处理我们的发票PDF文件的样式和布局。

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>";
    }
}
IRON VB CONVERTER ERROR developers@ironsoftware.com
$vbLabelText   $csharpLabel

最后,您将需要创建一个新的控制器,以便通过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}");
        }
    }
}
IRON VB CONVERTER ERROR developers@ironsoftware.com
$vbLabelText   $csharpLabel

发票输出

如何使用IronPDF创建.NET PDF API:图7 - PDF发票输出

容器部署注意事项

虽然本教程侧重于本地开发,但这里是关于将您的PDF API容器化的简要概述:

基础Dockerfile

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"]
IRON VB CONVERTER ERROR developers@ironsoftware.com
$vbLabelText   $csharpLabel

有关您的.NET PDF API的详细部署指南,请参阅:

错误处理最佳实践

为了设计更具容错性的程序,最佳实践是实施全局错误处理程序,以获得一致的错误响应,例如下面所示:

// 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));
    }
}
IRON VB CONVERTER ERROR developers@ironsoftware.com
$vbLabelText   $csharpLabel

对于特定的IronPDF故障排除场景,请参阅IronPDF故障排除指南

结论

您现在已经构建了一个强大的.NET PDF API,使用ASP.NET Core和IronPDF可以处理多种文档生成场景。 这个REST API为您的应用程序提供集中化PDF操作的坚实基础。

关键要点:

  • IronPDF使得Web API项目中的PDF生成变得简单,具有其基于Chrome的渲染
  • 您可以轻松调整Web API以编辑现有PDF文档,利用IronPDF的高级编辑工具
  • RESTful设计原则确保您的PDF API直观且易于维护
  • 适当的错误处理和安全措施对于生产至关重要
  • 通过异步操作和缓存进行性能优化可提高可扩展性
  • 您将拥有支持桌面和Web应用程序的可扩展文档解决方案

IronPDF允许开发人员高效地创建PDF文档、保存PDF文件和转换HTML,使其成为现代.NET Framework应用程序中的必备PDF文档API。

下一步

准备好在您的生产.NET PDF API中实施IronPDF了吗? 以下是您的下一步操作:

  1. 开始免费试用 - 在您的开发环境中测试IronPDF的全部功能
  2. Explore advanced features - Check out digital signatures, PDF forms, and other advanced PDF features
  3. 自信地扩展 - 查看许可选项以满足您的生产API需求

今天就构建您的.NET PDF API,并通过IronPDF在整个应用程序生态系统中简化文档生成!

常见问题解答

什么是.NET PDF API?

一个.NET PDF API是一个库,允许开发人员在.NET应用程序中创建、编辑和提取PDF内容。它简化了复杂的PDF任务并确保PDF文件的有效管理。

一个.NET PDF API如何能够使我的应用程序受益?

一个.NET PDF API可以通过提供一致性、可维护性和可扩展性来增强您的应用程序中PDF文件的管理,如生成发票、报告、证书或合同。

一个.NET PDF API 有哪些常见用例?

一个.NET PDF API 的常见用例包括在桌面和网络应用程序中生成发票、创建报告、制作证书和管理合同。

IronPDF如何简化PDF生成任务?

IronPDF通过提供强大的库简化了PDF生成任务,使得文档内容、PDF页面和表单字段的管理变得简单,更容易维护和扩展应用程序。

IronPDF能够处理PDF表单字段吗?

是的,IronPDF可以高效管理PDF表单字段,允许开发者在PDF文件中创建、填写和提取表单数据。

IronPDF适用于桌面和网络应用程序吗?

当然,IronPDF专为跨桌面和网络应用程序无缝工作而设计,提供一致且可扩展的PDF管理解决方案。

是什么让IronPDF成为.NET开发人员可靠的选择?

IronPDF是.NET开发人员可靠的选择,因为其使用简单、功能全面,并能够简化PDF任务,从而提高生产力和应用程序性能。

IronPDF支持PDF提取功能吗?

是的,IronPDF支持PDF提取功能,允许您有效地从PDF文件中提取文本、图像和其他数据。

IronPDF如何在管理PDF方面提高可扩展性?

IronPDF通过提供一个集中化的PDF生成服务来提高可扩展性,它可以在不牺牲性能的情况下处理日益增长的需求,非常适合增长中的应用程序。

IronPDF为.NET应用程序提供了什么样的支持?

IronPDF为.NET应用程序提供了广泛的支持,包括详细的文档、示例代码和响应迅速的支持团队,协助开发者集成PDF功能。

IronPDF 是否完全兼容 .NET 10?

是的——IronPDF 与 .NET 10 完全兼容。它支持 .NET 10 引入的所有性能、语言和运行时增强功能,并且可以像在 .NET 6、7、8 和 9 等以前的版本中一样,在 .NET 10 项目中开箱即用。

Curtis Chau
技术作家

Curtis Chau 拥有卡尔顿大学的计算机科学学士学位,专注于前端开发,精通 Node.js、TypeScript、JavaScript 和 React。他热衷于打造直观且美观的用户界面,喜欢使用现代框架并创建结构良好、视觉吸引力强的手册。

除了开发之外,Curtis 对物联网 (IoT) 有浓厚的兴趣,探索将硬件和软件集成的新方法。在空闲时间,他喜欢玩游戏和构建 Discord 机器人,将他对技术的热爱与创造力相结合。