How to Use Fluent Validation With IronPDF in C#
What is Fluent Validation?
FluentValidation is a .NET validation library that helps in building strongly typed validation rules. It uses a fluent interface and lambda expressions, making the code more readable and maintainable. Instead of using data annotations or manual validation in your model classes, you can use Fluent Validation to build a separate class for your validation logic.
Fluent Validation brings more flexibility to the validation game. With built-in validators for common scenarios, the ability to build custom validations, and a simple way to chain validation rules, Fluent Validation is a powerful tool in the .NET Core toolkit.
Understanding Fluent Validation
Fluent Validation is an open-source library for .NET that makes it easy to build validation rules for your model classes.
- Validators: Validators are classes that encapsulate the validation logic. They are typically created by inheriting from the
AbstractValidator<T>
base class. - Rules: A rule is a validation condition that a property must meet. Rules are defined using the
RuleFor
method in a validator class. - Validation Failures: If a rule fails, Fluent Validation creates a
ValidationFailure
object that contains details about the error, including the property name and error message.
What is IronPDF?
IronPDF - Convert HTML to PDF in C# is a powerful .NET library that allows you to generate PDF documents from HTML content. Whether you need to create invoices, reports, or any other type of document, IronPDF provides an easy-to-use solution. It seamlessly integrates with your ASP.NET Core applications, enabling you to generate high-quality PDF files with just a few lines of code.
Using Fluent Validation with IronPDF
Now that we understand what Fluent Validation and IronPDF are, let's see how they can be used together. This tutorial will help build an invoice generator, where the invoice content will be validated using FluentValidation in ASP.NET Core before generating the PDF using IronPDF.
Setting Up the Project
To begin, let's create a new Console Application in Visual Studio or your preferred development environment.
- Open Visual Studio and go to File > New > Project.
Select "Console App (ASP.NET Core)" as the project template and provide a name for your project.
Create a new Console Application
Click the Next button and configure your project by naming it and selecting the repository location.
Configure the new application
Click on the Next button and select the .NET Framework. The latest .NET Framework (7) is recommended.
.NET Framework selection
- Click on the Create button to create the project.
Install Required Packages
Once the project is created, add the necessary NuGet packages for Fluent Validation and IronPDF.
- Right-click on the project in the Solution Explorer and select "Manage NuGet Packages."
Search for "FluentValidation" and click "Install" to add the package to your project.
Install the FluentValidation package in NuGet Package Manager UI
- Similarly, search for "IronPDF - Powerful .NET PDF Library" and install the IronPDF package.
Alternatively, you can install IronPDF using NuGet Package Manager Console with the following command:
Install-Package IronPdf
Install the IronPdf package in the Package Manager Console
With the project set up and the required packages installed, let's move on to defining the PDF content class.
Defining the PDF Content
In this example, a simple invoice PDF will be created from the HTML codes in two classes: InvoiceContent
and InvoiceItem
.
using System.Collections.Generic;
using System.Linq;
public abstract class PdfContent
{
// Abstract method to generate the HTML string
public abstract string RenderHtml();
}
public class InvoiceContent : PdfContent
{
public string CustomerName { get; set; }
public string Address { get; set; }
public List<InvoiceItem> InvoiceItems { get; set; }
// Constructs the HTML representation of the invoice
public override string RenderHtml()
{
string invoiceItemsHtml = string.Join("", InvoiceItems.Select(item => $"<li>{item.Description}: {item.Price}</li>"));
return $"<h1>Invoice for {CustomerName}</h1><p>{Address}</p><ul>{invoiceItemsHtml}</ul>";
}
}
public class InvoiceItem
{
public string Description { get; set; }
public decimal Price { get; set; }
}
using System.Collections.Generic;
using System.Linq;
public abstract class PdfContent
{
// Abstract method to generate the HTML string
public abstract string RenderHtml();
}
public class InvoiceContent : PdfContent
{
public string CustomerName { get; set; }
public string Address { get; set; }
public List<InvoiceItem> InvoiceItems { get; set; }
// Constructs the HTML representation of the invoice
public override string RenderHtml()
{
string invoiceItemsHtml = string.Join("", InvoiceItems.Select(item => $"<li>{item.Description}: {item.Price}</li>"));
return $"<h1>Invoice for {CustomerName}</h1><p>{Address}</p><ul>{invoiceItemsHtml}</ul>";
}
}
public class InvoiceItem
{
public string Description { get; set; }
public decimal Price { get; set; }
}
Imports System.Collections.Generic
Imports System.Linq
Public MustInherit Class PdfContent
' Abstract method to generate the HTML string
Public MustOverride Function RenderHtml() As String
End Class
Public Class InvoiceContent
Inherits PdfContent
Public Property CustomerName() As String
Public Property Address() As String
Public Property InvoiceItems() As List(Of InvoiceItem)
' Constructs the HTML representation of the invoice
Public Overrides Function RenderHtml() As String
Dim invoiceItemsHtml As String = String.Join("", InvoiceItems.Select(Function(item) $"<li>{item.Description}: {item.Price}</li>"))
Return $"<h1>Invoice for {CustomerName}</h1><p>{Address}</p><ul>{invoiceItemsHtml}</ul>"
End Function
End Class
Public Class InvoiceItem
Public Property Description() As String
Public Property Price() As Decimal
End Class
In the code above, an abstract PdfContent
class is defined with an abstract method called RenderHtml
. The InvoiceContent
class extends PdfContent
and represents the content of the invoice PDF. It has properties for the customer's name, address, and a list of invoice items. The InvoiceItem
class contains two properties: 'Description' and 'Price'. The RenderHtml
method generates the HTML markup for the invoice based on the content.
Now that the PDF content is defined, let's move on to creating validation rules using Fluent Validation.
Creating Validation Rules
For building validation rules for the InvoiceContent
class, create a validator class called InvoiceContentValidator
. This class will inherit from AbstractValidator<InvoiceContent>
, which is provided by FluentValidation.
using FluentValidation;
public class InvoiceContentValidator : AbstractValidator<InvoiceContent>
{
public InvoiceContentValidator()
{
RuleFor(content => content.CustomerName).NotEmpty().WithMessage("Customer name is required.");
RuleFor(content => content.Address).NotEmpty().WithMessage("Address is required.");
RuleFor(content => content.InvoiceItems).NotEmpty().WithMessage("At least one invoice item is required.");
RuleForEach(content => content.InvoiceItems).SetValidator(new InvoiceItemValidator());
}
}
public class InvoiceItemValidator : AbstractValidator<InvoiceItem>
{
public InvoiceItemValidator()
{
RuleFor(item => item.Description).NotEmpty().WithMessage("Description is required.");
RuleFor(item => item.Price).GreaterThanOrEqualTo(0).WithMessage("Price must be greater than or equal to 0.");
}
}
using FluentValidation;
public class InvoiceContentValidator : AbstractValidator<InvoiceContent>
{
public InvoiceContentValidator()
{
RuleFor(content => content.CustomerName).NotEmpty().WithMessage("Customer name is required.");
RuleFor(content => content.Address).NotEmpty().WithMessage("Address is required.");
RuleFor(content => content.InvoiceItems).NotEmpty().WithMessage("At least one invoice item is required.");
RuleForEach(content => content.InvoiceItems).SetValidator(new InvoiceItemValidator());
}
}
public class InvoiceItemValidator : AbstractValidator<InvoiceItem>
{
public InvoiceItemValidator()
{
RuleFor(item => item.Description).NotEmpty().WithMessage("Description is required.");
RuleFor(item => item.Price).GreaterThanOrEqualTo(0).WithMessage("Price must be greater than or equal to 0.");
}
}
Imports FluentValidation
Public Class InvoiceContentValidator
Inherits AbstractValidator(Of InvoiceContent)
Public Sub New()
RuleFor(Function(content) content.CustomerName).NotEmpty().WithMessage("Customer name is required.")
RuleFor(Function(content) content.Address).NotEmpty().WithMessage("Address is required.")
RuleFor(Function(content) content.InvoiceItems).NotEmpty().WithMessage("At least one invoice item is required.")
RuleForEach(Function(content) content.InvoiceItems).SetValidator(New InvoiceItemValidator())
End Sub
End Class
Public Class InvoiceItemValidator
Inherits AbstractValidator(Of InvoiceItem)
Public Sub New()
RuleFor(Function(item) item.Description).NotEmpty().WithMessage("Description is required.")
RuleFor(Function(item) item.Price).GreaterThanOrEqualTo(0).WithMessage("Price must be greater than or equal to 0.")
End Sub
End Class
In the source code, the InvoiceContentValidator
class is defined, which inherits from AbstractValidator<InvoiceContent>
. Inside the constructor of the validator class, the RuleFor
method defines validation rules for each property of the InvoiceContent
class.
For example, RuleFor(content => content.CustomerName)
specifies that the customer name should not be empty. Similarly, validation rules are defined for the address and invoice items properties.
The RuleForEach
method iterates over each item in the InvoiceItems
list and applies the InvoiceItemValidator
. The InvoiceItemValidator
class contains validation rules for the InvoiceItem
class.
With these validation rules in place, let's move on to generating the PDF using IronPDF.
Generating PDF using IronPDF
IronPDF - Generate and Edit PDF Documents is a popular .NET library for creating and manipulating PDF documents. IronPDF will be used to generate the PDF based on the validated invoice content.
using IronPdf;
using FluentValidation;
public class PdfService
{
// Generates a PDF document for the provided content
public PdfDocument GeneratePdf<T>(T content) where T : PdfContent
{
// Validate the content using the appropriate validator
var validator = GetValidatorForContent(content);
var validationResult = validator.Validate(content);
// Check if validation is successful
if (!validationResult.IsValid)
{
throw new FluentValidation.ValidationException(validationResult.Errors);
}
// Generate the PDF using IronPDF
var renderer = new ChromePdfRenderer();
return renderer.RenderHtmlAsPdf(content.RenderHtml());
}
// Retrieves the appropriate validator for the content
private IValidator<T> GetValidatorForContent<T>(T content) where T : PdfContent
{
if (content is InvoiceContent)
{
return (IValidator<T>)new InvoiceContentValidator();
}
else
{
throw new NotSupportedException("Unsupported content type.");
}
}
}
using IronPdf;
using FluentValidation;
public class PdfService
{
// Generates a PDF document for the provided content
public PdfDocument GeneratePdf<T>(T content) where T : PdfContent
{
// Validate the content using the appropriate validator
var validator = GetValidatorForContent(content);
var validationResult = validator.Validate(content);
// Check if validation is successful
if (!validationResult.IsValid)
{
throw new FluentValidation.ValidationException(validationResult.Errors);
}
// Generate the PDF using IronPDF
var renderer = new ChromePdfRenderer();
return renderer.RenderHtmlAsPdf(content.RenderHtml());
}
// Retrieves the appropriate validator for the content
private IValidator<T> GetValidatorForContent<T>(T content) where T : PdfContent
{
if (content is InvoiceContent)
{
return (IValidator<T>)new InvoiceContentValidator();
}
else
{
throw new NotSupportedException("Unsupported content type.");
}
}
}
Imports IronPdf
Imports FluentValidation
Public Class PdfService
' Generates a PDF document for the provided content
Public Function GeneratePdf(Of T As PdfContent)(ByVal content As T) As PdfDocument
' Validate the content using the appropriate validator
Dim validator = GetValidatorForContent(content)
Dim validationResult = validator.Validate(content)
' Check if validation is successful
If Not validationResult.IsValid Then
Throw New FluentValidation.ValidationException(validationResult.Errors)
End If
' Generate the PDF using IronPDF
Dim renderer = New ChromePdfRenderer()
Return renderer.RenderHtmlAsPdf(content.RenderHtml())
End Function
' Retrieves the appropriate validator for the content
Private Function GetValidatorForContent(Of T As PdfContent)(ByVal content As T) As IValidator(Of T)
If TypeOf content Is InvoiceContent Then
Return DirectCast(New InvoiceContentValidator(), IValidator(Of T))
Else
Throw New NotSupportedException("Unsupported content type.")
End If
End Function
End Class
The PdfService
class provides a GeneratePdf
method. This method takes a PdfContent
object as input and generates the PDF document based on the validated content.
First, it retrieves the appropriate validator for the content by calling the GetValidatorForContent
method, which checks the type of content and returns the corresponding validator. In our case, we support InvoiceContent
and use the InvoiceContentValidator
.
Next, the content is validated using the validator by calling its Validate
method. The validation result is stored in a ValidationResult
object.
If the validation fails (!validationResult.IsValid
), a FluentValidation.ValidationException
is thrown with the validation errors. Otherwise, the PDF is generated using IronPDF.
An instance of ChromePdfRenderer is created to render the HTML content as a PDF. The RenderHtmlAsPdf method is called on the renderer
object, passing in the HTML generated by the content.RenderHtml
method, generating the PDF document.
Now that we have defined the PDF generation logic, let's handle any validation errors that may occur.
Handling Validation Errors
When a validation error occurs, we want to display an error message and handle it gracefully. Let's modify the Main
method of the Program
class to handle any exceptions and display meaningful messages to the user.
using System;
using System.Collections.Generic;
public class Program
{
static void Main(string[] args)
{
var pdfService = new PdfService();
// Test 1: Empty Customer Name
try
{
var invoiceContent = new InvoiceContent
{
CustomerName = "",
Address = "123 Main St, Anytown, USA",
InvoiceItems = new List<InvoiceItem> {
new InvoiceItem { Description = "Item 1", Price = 19.99M },
new InvoiceItem { Description = "Item 2", Price = 29.99M }
}
};
var pdfDocument = pdfService.GeneratePdf(invoiceContent);
pdfDocument.SaveAs("C:\\TestInvoice.pdf");
Console.WriteLine("PDF generated successfully!");
}
catch (Exception ex)
{
Console.WriteLine("Error generating PDF: " + ex.Message);
}
// Test 2: Empty InvoiceItems
try
{
var invoiceContent = new InvoiceContent
{
CustomerName = "John Doe",
Address = "123 Main St, Anytown, USA",
InvoiceItems = new List<InvoiceItem>() // Empty list
};
var pdfDocument = pdfService.GeneratePdf(invoiceContent);
pdfDocument.SaveAs("C:\\TestInvoice.pdf");
Console.WriteLine("PDF generated successfully!");
}
catch (Exception ex)
{
Console.WriteLine("Error generating PDF: " + ex.Message);
}
// Successful generation
try
{
var invoiceContent = new InvoiceContent
{
CustomerName = "John Doe",
Address = "123 Main St, Anytown, USA",
InvoiceItems = new List<InvoiceItem> {
new InvoiceItem { Description = "Item 1", Price = 19.99M },
new InvoiceItem { Description = "Item 2", Price = 29.99M }
}
};
var pdfDocument = pdfService.GeneratePdf(invoiceContent);
pdfDocument.SaveAs("C:\\TestInvoice.pdf");
Console.WriteLine("PDF generated successfully!");
}
catch (Exception ex)
{
Console.WriteLine("Error generating PDF: " + ex.Message);
}
}
}
using System;
using System.Collections.Generic;
public class Program
{
static void Main(string[] args)
{
var pdfService = new PdfService();
// Test 1: Empty Customer Name
try
{
var invoiceContent = new InvoiceContent
{
CustomerName = "",
Address = "123 Main St, Anytown, USA",
InvoiceItems = new List<InvoiceItem> {
new InvoiceItem { Description = "Item 1", Price = 19.99M },
new InvoiceItem { Description = "Item 2", Price = 29.99M }
}
};
var pdfDocument = pdfService.GeneratePdf(invoiceContent);
pdfDocument.SaveAs("C:\\TestInvoice.pdf");
Console.WriteLine("PDF generated successfully!");
}
catch (Exception ex)
{
Console.WriteLine("Error generating PDF: " + ex.Message);
}
// Test 2: Empty InvoiceItems
try
{
var invoiceContent = new InvoiceContent
{
CustomerName = "John Doe",
Address = "123 Main St, Anytown, USA",
InvoiceItems = new List<InvoiceItem>() // Empty list
};
var pdfDocument = pdfService.GeneratePdf(invoiceContent);
pdfDocument.SaveAs("C:\\TestInvoice.pdf");
Console.WriteLine("PDF generated successfully!");
}
catch (Exception ex)
{
Console.WriteLine("Error generating PDF: " + ex.Message);
}
// Successful generation
try
{
var invoiceContent = new InvoiceContent
{
CustomerName = "John Doe",
Address = "123 Main St, Anytown, USA",
InvoiceItems = new List<InvoiceItem> {
new InvoiceItem { Description = "Item 1", Price = 19.99M },
new InvoiceItem { Description = "Item 2", Price = 29.99M }
}
};
var pdfDocument = pdfService.GeneratePdf(invoiceContent);
pdfDocument.SaveAs("C:\\TestInvoice.pdf");
Console.WriteLine("PDF generated successfully!");
}
catch (Exception ex)
{
Console.WriteLine("Error generating PDF: " + ex.Message);
}
}
}
Imports System
Imports System.Collections.Generic
Public Class Program
Shared Sub Main(ByVal args() As String)
Dim pdfService As New PdfService()
' Test 1: Empty Customer Name
Try
Dim invoiceContent As New InvoiceContent With {
.CustomerName = "",
.Address = "123 Main St, Anytown, USA",
.InvoiceItems = New List(Of InvoiceItem) From {
New InvoiceItem With {
.Description = "Item 1",
.Price = 19.99D
},
New InvoiceItem With {
.Description = "Item 2",
.Price = 29.99D
}
}
}
Dim pdfDocument = pdfService.GeneratePdf(invoiceContent)
pdfDocument.SaveAs("C:\TestInvoice.pdf")
Console.WriteLine("PDF generated successfully!")
Catch ex As Exception
Console.WriteLine("Error generating PDF: " & ex.Message)
End Try
' Test 2: Empty InvoiceItems
Try
Dim invoiceContent As New InvoiceContent With {
.CustomerName = "John Doe",
.Address = "123 Main St, Anytown, USA",
.InvoiceItems = New List(Of InvoiceItem)()
}
Dim pdfDocument = pdfService.GeneratePdf(invoiceContent)
pdfDocument.SaveAs("C:\TestInvoice.pdf")
Console.WriteLine("PDF generated successfully!")
Catch ex As Exception
Console.WriteLine("Error generating PDF: " & ex.Message)
End Try
' Successful generation
Try
Dim invoiceContent As New InvoiceContent With {
.CustomerName = "John Doe",
.Address = "123 Main St, Anytown, USA",
.InvoiceItems = New List(Of InvoiceItem) From {
New InvoiceItem With {
.Description = "Item 1",
.Price = 19.99D
},
New InvoiceItem With {
.Description = "Item 2",
.Price = 29.99D
}
}
}
Dim pdfDocument = pdfService.GeneratePdf(invoiceContent)
pdfDocument.SaveAs("C:\TestInvoice.pdf")
Console.WriteLine("PDF generated successfully!")
Catch ex As Exception
Console.WriteLine("Error generating PDF: " & ex.Message)
End Try
End Sub
End Class
In the code above, try-catch
blocks are used to catch any exceptions that may occur. If an exception is caught, an error message will be shown to the user using Console.WriteLine
.
Now let's test this application with different scenarios to validate the PDF generation and the validation rules.
Testing the Application
In the code example, there are three scenarios to test:
- Empty customer name: Leave the customer name empty to trigger a validation error.
- Empty invoice items: Provide an empty list of invoice items to trigger a validation error.
- Successful generation: Provide valid content to generate the PDF successfully.
Run the application and observe the output in the console.
Error generating PDF: Validation failed:
-- CustomerName: Customer name is required. Severity: Error
Error generating PDF: Validation failed:
-- InvoiceItems: At least one invoice item is required. Severity: Error
PDF generated successfully!
The output error in the Console
The output PDF file
As expected, validation errors are shown for the first two scenarios and a success message for the third scenario.
Conclusion
This tutorial explored Fluent Validation and how to use it with IronPDF to generate PDF documents. Starting by setting up a Console Application and defining the PDF content class. Then, created validation rules using Fluent Validation and tested the PDF generation with different scenarios.
Fluent Validation provides a flexible and easy-to-use approach for validating objects in .NET applications. It allows you to define validation rules in a strongly typed manner, customize error messages, and handle validation errors gracefully.
IronPDF Free Trial & Licensing Information offers a free trial, and the license starts from $499 per developer.
Frequently Asked Questions
How can I integrate Fluent Validation with PDF generation in C#?
To integrate Fluent Validation with PDF generation in C#, you can set up a Console Application in Visual Studio, install the FluentValidation and IronPDF packages via NuGet, and define your model validation logic using Fluent Validation while generating PDFs using IronPDF.
What steps are involved in setting up a project for PDF generation and validation?
To set up a project, create a new Console Application in Visual Studio, install the IronPDF and FluentValidation packages through NuGet, and then define your PDF content and validation rules using the respective libraries.
How can I generate a PDF from HTML content using a .NET library?
You can generate a PDF from HTML content using IronPDF's RenderHtmlAsPdf
method, which allows you to convert HTML strings or files into high-quality PDFs.
What is the purpose of the PdfService class in the tutorial?
The PdfService class in the tutorial is designed to manage PDF generation by first validating the content using Fluent Validation. Upon successful validation, it uses IronPDF's ChromePdfRenderer
and RenderHtmlAsPdf
methods to create the PDF.
How are validation rules defined using Fluent Validation?
Validation rules in Fluent Validation are defined by creating a validator class that inherits from AbstractValidator
. Within this class, the RuleFor
method is used to specify conditions for each property, allowing for custom error messages and chaining of rules.
What happens if validation fails during PDF generation?
If validation fails, Fluent Validation throws a ValidationException
that contains detailed information about the validation errors, which can be used to inform the user of what went wrong.
Can I use Fluent Validation for complex object validation?
Yes, Fluent Validation supports complex object validation through the use of child validators, allowing you to validate nested properties and collections within your model.
How can I customize error messages in Fluent Validation?
Custom error messages in Fluent Validation can be defined using the WithMessage
method for each validation rule specified with RuleFor
.
Is there a trial version available for the PDF generation library?
Yes, IronPDF offers a free trial version for developers to test the library's capabilities, with licensing options available starting at $499 per developer.