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. This is done by providing a fluent interface and lambda expressions, which makes 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 validation, 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.

  1. Validators: Validators are classes that encapsulate the validation logic. They are typically created by inheriting from the AbstractValidator<T> base class.
  2. Rules: A rule is a validation condition that a property must meet. Rules are defined using the RuleFor method in a validator class.
  3. 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 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 we can use them together. In our tutorial, we'll build an invoice generator, where the invoice content will be validated using FluentValidation in ASP.NET Core before generating the PDF using IronPDF.

Now let's get started!

Setting Up the Project

To begin, let's create a new console application in Visual Studio or your preferred development environment.

  1. Open Visual Studio and go to File > New > Project.
  2. Select "Console App (ASP.NET Core)" as the project template and provide a name for your project.

    How to Use Fluent Validation With IronPDF in C#: Figure 1

  3. Click the Next button and configure your project by giving the name and selecting the repository location.

    How to Use Fluent Validation With IronPDF in C#: Figure 2

  4. Click on the "Next" button and select the .NET Framework. Latest .NET Framework (7) is recommended.

    How to Use Fluent Validation With IronPDF in C#: Figure 3

  5. Click on "Create" button to create the project.

Install Required Packages

Once the project is created, we need to add the necessary NuGet packages for Fluent Validation and IronPDF.

  1. Right-click on the project in the Solution Explorer and select "Manage NuGet Packages."
  2. Search for "FluentValidation" and click "Install" to add the package to your project.

    How to Use Fluent Validation With IronPDF in C#: Figure 4

  3. Similarly, search for "IronPDF" and install the IronPDF package.

However, you can also install IronPDF using NuGet Package Manager Console using the following command:

```shell
:ProductInstall

![How to Use Fluent Validation With IronPDF in C#: Figure 5](/static-assets/pdf/blog/fluent-validation-csharp/fluent-validation-csharp-5.webp)

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 our example, we will create a simple invoice PDF. We'll define two classes: `InvoiceContent` and `InvoiceItem`.

```cs  

    public abstract class PdfContent
    {
        public abstract string RenderHtml();
    }

    public class InvoiceContent : PdfContent
    {
        public string CustomerName { get; set; }
        public string Address { get; set; }
        public List<InvoiceItem> InvoiceItems { get; set; }

        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; }
    }

In the code above, we have defined an abstract PdfContent class with an abstract method called RenderHtml. The InvoiceContent class extends PdfContent and represents the content of our invoice PDF. It has properties for customer 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 we have our PDF content defined, let's move on to creating validation rules using Fluent Validation.

Creating Validation Rules

For building validation rules for our InvoiceContent class, we'll create a validator class called InvoiceContentValidator. This class will inherit from AbstractValidator<InvoiceContent>, which is provided by Fluent Validation.

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
VB   C#

In the above source code, we define the InvoiceContentValidator class, which inherits from AbstractValidator<InvoiceContent>. Inside the constructor of the validator class, we use the RuleFor method to define validation rules for each property of the InvoiceContent class.

For example, we use RuleFor(content => content.CustomerName) to define a new rule that the customer name should not be empty. We chain the NotEmpty method to specify this validation rule. Similarly, we define validation rules for the address and invoice items properties.

To validate the invoice items, we use the RuleForEach method to iterate over each item in the InvoiceItems list and apply a validator called InvoiceItemValidator. The InvoiceItemValidator class is defined separately and contains validation rules for the InvoiceItem class.

With our validation rules in place, let's move on to generating the PDF using IronPDF.

Generating PDF using IronPDF

IronPDF is a popular .NET library for creating and manipulating PDF documents. We'll use IronPDF to generate the PDF based on the validated invoice content.

using IronPdf;
using FluentValidation;

public class PdfService
{
    public PdfDocument GeneratePdf<T>(T content) where T : PdfContent
    {
        var validator = GetValidatorForContent(content);
        FluentValidation.Results.ValidationResult validationResult = validator.Validate(content);

        if (!validationResult.IsValid)
        {
            throw new FluentValidation.ValidationException(validationResult.Errors);
        }

        var htmlToPdf = new ChromePdfRenderer();
        return htmlToPdf.RenderHtmlAsPdf(content.RenderHtml());
    }

    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
{
    public PdfDocument GeneratePdf<T>(T content) where T : PdfContent
    {
        var validator = GetValidatorForContent(content);
        FluentValidation.Results.ValidationResult validationResult = validator.Validate(content);

        if (!validationResult.IsValid)
        {
            throw new FluentValidation.ValidationException(validationResult.Errors);
        }

        var htmlToPdf = new ChromePdfRenderer();
        return htmlToPdf.RenderHtmlAsPdf(content.RenderHtml());
    }

    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
	Public Function GeneratePdf(Of T As PdfContent)(ByVal content As T) As PdfDocument
		Dim validator = GetValidatorForContent(content)
		Dim validationResult As FluentValidation.Results.ValidationResult = validator.Validate(content)

		If Not validationResult.IsValid Then
			Throw New FluentValidation.ValidationException(validationResult.Errors)
		End If

		Dim htmlToPdf = New ChromePdfRenderer()
		Return htmlToPdf.RenderHtmlAsPdf(content.RenderHtml())
	End Function

	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
VB   C#

In the source code above, we define a PdfService class that provides a GeneratePdf method. This method takes a PdfContent object as input and generates the PDF document based on the validated content.

First, we retrieve the appropriate validator for the content by calling the GetValidatorForContent method. This method checks the type of the content and returns the corresponding validator. In our case, we only support InvoiceContent and use the InvoiceContentValidator.

Next, we validate the content using the validator by calling its validate method. The validation result is stored in a ValidationResult object.

If the validation fails (!validationResult.IsValid), we throw a FluentValidation.ValidationException with the validation errors. Otherwise, we proceed to generate the PDF using IronPDF.

We create an instance of ChromePdfRenderer to render the HTML content as a PDF. We call the RenderHtmlAsPdf method on the htmlToPdf object and pass in the HTML generated by the content.RenderHtml method. This generates 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.

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
        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);
        }
    }
}
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
        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);
        }
    }
}
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
		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
VB   C#

In the code above, we wrap the PDF generation code in a try-catch block to catch any exceptions that may occur. If an exception is caught, we display an error message to the user using Console.WriteLine.

Now, let's test our application with different scenarios to validate the PDF generation and the validation rules.

Testing the Application

In our code example, we have three scenarios to test:

  1. Empty customer name: We intentionally leave the customer name empty to trigger a validation error.
  2. Empty invoice items: We provide an empty list of invoice items to trigger a validation error.
  3. Successful generation: We 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!

How to Use Fluent Validation With IronPDF in C#: Figure 6

How to Use Fluent Validation With IronPDF in C#: Figure 7

As expected, we receive validation errors for the first two scenarios and a success message for the third scenario.

Conclusion

In this tutorial, we explored Fluent Validation and learned how to use it with IronPDF to generate PDF documents. We started by setting up a console application and defining the PDF content class. Then, we 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 offers free trial and license starts from $749.