푸터 콘텐츠로 바로가기
IRONPDF 사용

How to create .NET PDF API Using IronPDF

When working with modern applications, .NET developers like yourself may find themselves needing to build a centralized PDF generation service. Whether you're generating invoices, reports, certificates, or contracts, having a dedicated .NET PDF API can be beneficial for efficiently managing PDF files. So how can it improve your PDF generation tasks? It does this through providing consistency, maintainability, and scalability across your desktop and web applications. Never before has it been easier to manage document content, PDF pages, and PDF form fields.

In this tutorial, you'll learn how to build a production-ready PDF API using ASP.NET Core and IronPDF, a powerful .NET PDF library. We'll create RESTful endpoints that can generate PDFs from HTML, merge documents, add watermarks, and handle various real-world PDF generation scenarios in your Web API.

Why Build a Dedicated PDF API?

Before diving into the code, let's understand why creating a dedicated PDF API makes sense:

  • Centralized Logic: All PDF generation logic lives in one place, making maintenance and updates easier
  • Microservice Architecture: Perfect for service-oriented architectures where different applications need PDF capabilities
  • Performance Optimization: Easier to scale and optimize a dedicated service for large PDF files, multiple pages, and dynamic data.
  • Language Agnostic: Any client application can consume the API regardless of programming language
  • Consistent Output: Ensures all PDF documents across your organization maintain consistent document layout, paragraph formatting, and PDF content.

Ready to start building? Download IronPDF's free trial and follow along with this tutorial to programmatically create PDF files in your .NET Framework projects.

IronPDF: The Complete .NET PDF Library

IronPDF stands out as the premier PDF library for .NET developers, offering a comprehensive set of features that make PDF generation in Web API projects straightforward and reliable. It's built on a Chrome rendering engine, which ensures pixel-perfect HTML-to-PDF conversions, often in just a few lines of code. It does all of this while maintaining all styling, JavaScript execution, and responsive layouts.

Key capabilities that make IronPDF ideal for .NET PDF API development:

  • Chrome-Based Rendering: Leverages Google Chrome's rendering engine for converting PDF documents from HTML content accurately, with full support for embedded images and other web assets
  • Rich Feature Set: Supports the editing of new and existing documents with digital signatures, PDF forms, annotations, encryption, compression, and more
  • Create Secure PDF Documents: Manage sensitive PDF content with encryption, digital signatures, and document protection.
  • Multiple Input Formats: Use HTML, URLs, images, and Office documents to create PDF documents
  • Advanced Manipulation: Merge PDF pages, split documents, apply watermarks, create interactive PDF forms, and manipulate PDF files programmatically.
  • Cross-Platform Support: Works on Windows, Linux, macOS, Docker, and cloud platforms
  • Performance Optimized: Async operations, efficient memory management, and fast rendering

How to Set Up Your PDF Document API Project?

Let's start by creating a new ASP.NET Core Web API project and installing the necessary packages.

Prerequisites

  • .NET 6.0 SDK or later
  • Visual Studio 2022 or Visual Studio Code
  • Postman or a similar API testing tool for testing your PDF REST API

Creating the Project

First, let's create the project within which we will build our PDF generation tool.

dotnet new webapi -n PdfApiService
cd PdfApiService

Installing IronPDF

The next step is to add IronPDF to your project via NuGet:

dotnet add package IronPdf

Or, using the NuGet Package Manager Console in Visual Studio:

Install-Package IronPdf

Project Structure

An essential aspect of C# development is maintaining a clean and well-structured project folder. For example:

How to Create Your First PDF Endpoint?

Let's build a simple endpoint that converts HTML to PDF format. First, create the service interface and implementation:

Creating the PDF Service

First, we will add the following to our IPdfService.cs file:

public interface IPdfService
{
    byte[] GeneratePdfFromHtml(string htmlContent);
    byte[] GeneratePdfFromUrl(string url);
}
public interface IPdfService
{
    byte[] GeneratePdfFromHtml(string htmlContent);
    byte[] GeneratePdfFromUrl(string url);
}
$vbLabelText   $csharpLabel

In the PdfService.cs file, we will add this:

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;
    }
}
$vbLabelText   $csharpLabel

The PdfService handles the core process of converting HTML into PDF. Utilizing IronPDF’s ChromePdfRenderer, this class is set up with sensible defaults like page margins and background rendering to produce a polished final document.

When the controller passes in raw HTML, the service uses IronPDF to render it into a professional-quality PDF and returns the result as byte data, ready to download. Additionally, it can also handle entire web pages by converting a URL directly into a PDF.

Creating the Controller

Now it's time to create the controller for our API. This will provide an API endpoint capable of generating PDF files from HTML. It will then be able to download and save PDF documents to your system for further use or sharing.

// 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}");
        }
    }
}
$vbLabelText   $csharpLabel

Then, in the HtmlRequest.cs file, we will add this:

// 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";
}
$vbLabelText   $csharpLabel

In the first file, we set up a straightforward API endpoint that turns HTML into a downloadable PDF. When someone sends HTML content to the api/pdf/html-to-pdf route with a simple POST request, the PdfController passes the job of converting it into a PDF to a dedicated service.

Once the PDF is created, the controller hands it back to the user as a ready-to-download file. The request itself is structured using the HtmlRequest model, which carries both the raw HTML and an optional file name for the final document. In short, this setup makes it easy for clients to send HTML and instantly receive a polished PDF in return.

Registering Services

Update your Program.cs to register the PDF service:

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();
$vbLabelText   $csharpLabel

How to Handle Different Response Types?

Your API should support different ways of returning PDFs based on client needs:

[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);
     }
 }
$vbLabelText   $csharpLabel

Here, we have added a more flexible PDF generation endpoint to the controller. Instead of always forcing a file download, the GeneratePdf method lets the client choose how they want the result returned. This option offers flexibility, allowing PDFs to be displayed in various formats: as a downloadable file, directly in the browser, or encoded as a Base64 string for easy use in APIs.

The request is defined by the PdfRequest model, which builds on the earlier HtmlRequest and adds a ResponseType option. In short, this gives users more control over how they receive their PDFs, making the API more versatile and user-friendly.

Now, when we run our program, we'll see this output on Swagger.

How to create .NET PDF API Using IronPDF: Figure 4 - Swagger UI

How to Implement Common PDF Operations?

Let's expand our service to handle various PDF generation scenarios:

URL to PDF Conversion

[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; }
}
$vbLabelText   $csharpLabel

This endpoint lets clients send a URL and get back a ready-to-download PDF of that webpage. When a POST /api/pdf/url-to-pdf request comes in, the controller uses _pdfService to convert the given URL into PDF bytes in the background, then returns them as a file download. If something goes wrong during conversion, it gracefully responds with a clear error message.

Let's try using the URL "https://www.apple.com/nz" and test the POST request. Below is the output we obtained.

Output

How to create .NET PDF API Using IronPDF: Figure 5 - URL PDF output

Adding Custom Watermarks

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;
}
$vbLabelText   $csharpLabel

Here, we are just manually loading a local file for testing purposes. However, you can adjust this so your PDF API generates a PDF document, and then apply a custom watermark to it with ease.

Watermark Output

How to create .NET PDF API Using IronPDF: Figure 6 - Watermark output from code example above

How to Add Dynamic Data with Templates

For real-world applications, you'll often need to generate PDFs from templates with dynamic data:

[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";
}
$vbLabelText   $csharpLabel

For more advanced template scenarios with Razor, Handlebars, or other engines, check out IronPDF's HTML to PDF documentation. You can also explore CSHTML to PDF conversion for MVC applications and Razor to PDF for Blazor applications.

How to Optimize Performance?

When building a production PDF API, performance is crucial. Here are key optimization strategies:

Async Operations

When building projects that involve the use of I/O operations, it is wise to use asynchronous coding. This is especially helpful if your PDF content comes from external resources like:

  • Downloading HTML pages (RenderUrlAsPdf)
  • Fetching images, CSS, or fonts over HTTP
  • Reading/writing files to disk or cloud storage

These operations can then block a thread, but using async prevents your API thread from waiting idle.

Example:

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;
    });
}
$vbLabelText   $csharpLabel

Rendering Options

Configure IronPDF for optimal performance:

_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
$vbLabelText   $csharpLabel

How to Secure Your PDF API?

Security is essential for any production API. Here's a simple API key authentication approach:

// 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>();
$vbLabelText   $csharpLabel

For more advanced authentication scenarios, consider:

Real-World Example: Invoice Generation API

Let's build a practical invoice generation endpoint that demonstrates a complete implementation. This example shows how a production .NET PDF API can generate professional invoices with dynamic data.

지금 바로 IronPDF으로 시작하세요.
green arrow pointer

First, we'll create a new file in our Models folder. Here, I've called mine Invoice.cs. Then, add the following code to your new file.

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;
}
$vbLabelText   $csharpLabel

Then, we'll need to create a new service file for our invoice generator. In your Services folder, add the following code. For mine, I made a new file called InvoiceService.cs. This code will handle the styling and layout of our Invoice PDF file.

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>";
    }
}
$vbLabelText   $csharpLabel

Finally, you will need to create a new Controller in order to access and create a new Invoice using the 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}");
        }
    }
}
$vbLabelText   $csharpLabel

Invoice Output

How to create .NET PDF API Using IronPDF: Figure 7 - PDF Invoice output

Container Deployment Considerations

While this tutorial focuses on local development, here's a brief overview of containerizing your PDF API:

Basic 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 .
<h1>IronPDF requires additional dependencies on Linux</h1>
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 .
<h1>IronPDF requires additional dependencies on Linux</h1>
RUN apt-get update && apt-get install -y \
    libgdiplus \
    libc6-dev \
    libx11-dev \
    && rm -rf /var/lib/apt/lists/*     
ENTRYPOINT ["dotnet", "PdfApiService.dll"]
$vbLabelText   $csharpLabel

For detailed deployment guides for your .NET PDF API, see:

Error Handling Best Practices

For a more fault-tolerant program, the best practices are to implement a global error handler for consistent error responses, such as below:

// 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));
    }
}
$vbLabelText   $csharpLabel

For specific IronPDF troubleshooting scenarios, refer to the IronPDF troubleshooting guide.

Conclusion

You've now built a robust .NET PDF API using ASP.NET Core and IronPDF that can handle various document generation scenarios. This REST API provides a solid foundation for centralized PDF operations in your applications.

Key takeaways:

  • IronPDF makes PDF generation in Web API projects straightforward with its Chrome-based rendering
  • You can easily adjust your Web API to edit existing PDF documents with IronPDF's advanced editing tools
  • RESTful design principles ensure your PDF API is intuitive and maintainable
  • Proper error handling and security measures are essential for production
  • Performance optimization through async operations and caching improves scalability
  • You will have support for desktop and web applications with scalable document solutions

IronPDF allows developers to create PDF documents, save PDF files, and convert HTML efficiently, making it the essential PDF document API for modern .NET Framework applications.

Next Steps

Ready to implement IronPDF in your production .NET PDF API? Here are your next actions:

  1. Start your free trial - Test IronPDF with full functionality in your development environment
  2. Explore advanced features - Check out digital signatures, PDF forms, and other advanced PDF features
  3. Scale with confidence - Review licensing options for your production API needs

Build your .NET PDF API today and streamline document generation across your entire application ecosystem with 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는 사용 편의성, 포괄적인 기능, PDF 작업을 간소화하여 생산성과 애플리케이션 성능을 향상시키는 기능으로 인해 .NET 개발자에게 신뢰할 수 있는 선택입니다.

IronPDF는 PDF 추출 기능을 지원하나요?

예, IronPDF는 PDF 추출 기능을 지원하므로 PDF 문서에서 텍스트, 이미지 및 기타 데이터를 효율적으로 추출할 수 있습니다.

IronPDF는 PDF 관리의 확장성을 어떻게 개선하나요?

IronPDF는 성능 저하 없이 증가하는 수요를 처리할 수 있는 중앙 집중식 PDF 생성 서비스를 제공함으로써 확장성을 향상시켜 애플리케이션 성장에 이상적입니다.

IronPDF는 .NET 애플리케이션에 대해 어떤 종류의 지원을 제공하나요?

IronPDF는 개발자가 PDF 기능을 통합하는 데 도움이 되는 자세한 문서, 샘플 코드 및 대응 지원 팀을 포함하여 .NET 애플리케이션에 대한 광범위한 지원을 제공합니다.

IronPDF는 .NET 10과 완벽하게 호환되나요?

예 - IronPDF는 .NET 10과 완벽하게 호환됩니다. .NET 10이 도입한 모든 성능, 언어 및 런타임 개선 사항을 지원하며 .NET 6, 7, 8, 9와 같은 이전 버전과 마찬가지로 .NET 10 프로젝트에서 바로 작동합니다.

커티스 차우
기술 문서 작성자

커티스 차우는 칼턴 대학교에서 컴퓨터 과학 학사 학위를 취득했으며, Node.js, TypeScript, JavaScript, React를 전문으로 하는 프론트엔드 개발자입니다. 직관적이고 미적으로 뛰어난 사용자 인터페이스를 만드는 데 열정을 가진 그는 최신 프레임워크를 활용하고, 잘 구성되고 시각적으로 매력적인 매뉴얼을 제작하는 것을 즐깁니다.

커티스는 개발 분야 외에도 사물 인터넷(IoT)에 깊은 관심을 가지고 있으며, 하드웨어와 소프트웨어를 통합하는 혁신적인 방법을 연구합니다. 여가 시간에는 게임을 즐기거나 디스코드 봇을 만들면서 기술에 대한 애정과 창의성을 결합합니다.