avatarJustin Muench

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

4426

Abstract

ne).NotEmpty().Matches(<span class="hljs-string">@"^\d{3}-\d{3}-\d{4}$"</span>); } }</pre></div><p id="4282">The class inherits from AbstractValidator with the type of the class to be validated. The validation then takes place in the validator class in the constructor.</p><p id="78d3">I have checked various conditions, whether the field is empty and meets a certain length and format. Practically, these conditions can be read well. Also, the use of regex is possible.</p><p id="8cf2">Inside the controller method, we still need to perform this validation.</p><div id="4f86"><pre>[<span class="hljs-meta">HttpPost</span>] <span class="hljs-function"><span class="hljs-keyword">public</span> IActionResult <span class="hljs-title">CreateCustomer</span>(<span class="hljs-params">[FromBody] CustomerCreateRequest request</span>)</span> { <span class="hljs-keyword">var</span> validator = <span class="hljs-keyword">new</span> CustomerCreateRequestValidator(); <span class="hljs-keyword">var</span> validationResult = validator.Validate(request);

<span class="hljs-keyword">if</span> (validationResult.IsValid == <span class="hljs-literal">false</span>) { <span class="hljs-keyword">return</span> BadRequest(validationResult.Errors[<span class="hljs-number">0</span>].ErrorMessage); }

<span class="hljs-keyword">return</span> Ok(); }</pre></div><p id="f8f3">The example project can be found on <a href="https://github.com/muench-develops/MediumFluentValidation">GitHub</a>.</p><p id="1c75">However, only the incoming data should be validated [1]. The primary business logic should be covered by unit tests [1].</p><h1 id="eb43">Best Practices</h1><ul><li>Name your validators after the data contracts they are validating [1]. This clarifies which validator should be used for a particular data contract and makes it easier to find and maintain the validator code.</li><li>Use the built-in validation rules provided by FluentValidation where possible. These are well-tested and can be easily reused.</li><li>Avoid duplicating validation logic across multiple validators. If multiple validators need to perform the same validation logic, extract that logic into a separate helper method that can be called from multiple validators.</li><li>Use the <code>RuleFor</code> method to declare validation rules for a specific property of a data contract. This makes it straightforward to which property a validation rule applies.</li><li>Use the <code>When</code> method to apply conditional validation rules. This allows you to change the validation logic based on the value of other properties in the data contract.</li></ul><h1 id="fbe4">Domain Model vs. Data Contract</h1><p id="78e2">It is a best practice to separate the domain model from data contracts in an ASP.NET 6.0 project. The domain model represents the business logic and rules of the application, while data contracts are used to define the structure of data being passed between the client and server.</p><p id="9826">Keeping these two concerns separate allows for more flexibility and maintainability in the application. The domain model can evolve and change without affecting the data contracts. Changing or adding new data contracts does not affect the domain model.</p><p id="60f9">This separation also makes it easier to unit test the domain logic, as it can be tested in isolation from the data contracts. Additionally, it can be easier to version the data contracts and handle backward compatibility.</p><h1 id="31c0">Demo — Nested objects</h1><p id="d0e2">Let’s assume our customers also has a field address, another class.</p><div id="12f5"><pre><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">CustomerCreateRequest</span> { <span class="hljs-keyword">public</span> <span class="hljs-built_in">string</span> Name { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; } <span class="hljs-keyword">public</span> <span class="hljs-built_in">string</span> Email { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; } <span class="hljs-keyword">public</span> <span class="hljs-built_in">string</span> Phone { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

<span class="hljs-keyword">public</span> Address Address { <span class="hljs-keyword">get</span>; <span class="hljs-key

Options

word">set</span>; } }

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Address</span> { <span class="hljs-keyword">public</span> <span class="hljs-built_in">string</span> Street { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; } <span class="hljs-keyword">public</span> <span class="hljs-built_in">string</span> City { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; } <span class="hljs-keyword">public</span> <span class="hljs-built_in">string</span> State { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; } <span class="hljs-keyword">public</span> <span class="hljs-built_in">string</span> ZipCode { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; } }</pre></div><p id="fcaa">How do we validate this? For this, we have to go back to our validator.</p><div id="0f41"><pre><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">CustomerCreateRequestValidator</span> : <span class="hljs-title">AbstractValidator</span><<span class="hljs-title">CustomerCreateRequest</span>> { <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">CustomerCreateRequestValidator</span>()</span> { RuleFor(x => x.Name).NotEmpty().Length(<span class="hljs-number">0</span>,<span class="hljs-number">100</span>); RuleFor(x => x.Email).NotEmpty().EmailAddress(); RuleFor(x => x.Phone).NotEmpty().Matches(<span class="hljs-string">@"^\d{3}-\d{3}-\d{4}$"</span>);

    RuleFor(x =&gt; x.Address).SetValidator(<span class="hljs-keyword">new</span> AddressValidator());
}

}

<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">AddressValidator</span> : <span class="hljs-title">AbstractValidator</span><<span class="hljs-title">Address</span>> { <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">AddressValidator</span>()</span> { RuleFor(x => x.Street).NotEmpty().Length(<span class="hljs-number">0</span>,<span class="hljs-number">100</span>); RuleFor(x => x.City).NotEmpty().Length(<span class="hljs-number">0</span>,<span class="hljs-number">100</span>); RuleFor(x => x.State).NotEmpty().Length(<span class="hljs-number">0</span>,<span class="hljs-number">100</span>); RuleFor(x => x.ZipCode).NotEmpty().Length(<span class="hljs-number">0</span>,<span class="hljs-number">100</span>); } }</pre></div><p id="df50">We create another validator and set it. We do this because otherwise, we would have to check multiple times if the Address is not null. To avoid this duplicating code logic, we set another validator.</p><h1 id="0178">Conclusion</h1><p id="3c76">In conclusion, FluentValidation is a powerful tool for validating data in an ASP.NET 6.0 project. By following best practices such as naming validators after the data contracts they are validating, using built-in validation rules, avoiding duplication of validation logic, and applying conditional validation, developers can create maintainable and efficient validation logic.</p><p id="755e">Additionally, it is essential to separate the domain model from the data contracts to achieve more flexibility, maintainability, and testability in the application.</p><p id="ecd9">The two simple demos in this post demonstrate how FluentValidation can be used to validate data and how to handle nested object validation. By following the best practices and understanding the difference between data contracts and domain models, developers can create robust and effective validation logic in their applications.</p><div id="62c0"><pre>Make sure to<span class="hljs-built_in"> check </span>out my other Posts!

Want to connect<span class="hljs-built_in"> and </span>stay up-to-date on AI, tech,<span class="hljs-built_in"> and </span>.NET development?

Follow me on Twitter<span class="hljs-built_in"> and </span>LinkedIn - I'm always happy to hear from you.</pre></div><h2 id="61c7">References</h2><ol><li><a href="https://app.pluralsight.com/library/courses/fluentvalidation-fundamentals/table-of-contents">FluentValidation Fundamentals</a> By Vladimir Khorikov</li></ol></article></body>

Get Started with FluentValidation in ASP.NET 6: A Step-by-Step Guide

Photo by Jaimie Harmsen on Unsplash

In this post, I’ll guide you through the process of getting started with FluentValidation in ASP.NET 6. FluentValidation is a powerful library for performing data validation in a fluent, expressive way, and it is especially well-suited to use in ASP.NET 6 projects.

I’ll show you how to set up FluentValidation in your ASP.NET 6 project and walk you through some examples of FluentValidation to validate different types of user input. By the end of this tutorial, you’ll understand how to use FluentValidation to ensure that your application receives accurate and reliable data. Let’s dive in!

Validation

Validation is the process of ensuring that some data is correct [1]. This can include checking that data is in the correct format, meets specific criteria, or is within certain boundaries. Validation is an essential step in any data-driven process, as it helps to ensure the integrity and reliability of the data being used.

Whether you are collecting data from users, importing data from external sources, or generating data within your application, it is essential to validate it to ensure that it is accurate and usable. Data errors can lead to incorrect results, poor decision-making, and many other problems without proper validation.

Demo — Validating Input

I created a simple API for creating a customer. I do not process the customer for the example. It is only about validation.

Let’s begin with creating a request class for the creation of a new customer.

public class CustomerCreateRequest
{
    public string Name { get; set; }
    public string Email { get; set; }
    public string Phone { get; set; }
}

And then create a controller.

public class CustomerController : ControllerBase
{
    [HttpPost]
    public IActionResult CreateCustomer([FromBody] CustomerCreateRequest request)
    {
        return Ok();
    }
}

Of course, we could now validate the fields of the request class by some If queries, but this bloats the controller method. For this reason, we want to use FluentValidation. To do this, we must first install the package.

I created a folder for the validators to keep some order and created a CustomerCreateRequestValidator class containing the validation logic.

public class CustomerCreateRequestValidator : AbstractValidator<CustomerCreateRequest>
{
    public CustomerCreateRequestValidator()
    {
        RuleFor(x => x.Name).NotEmpty().Length(0,100);
        RuleFor(x => x.Email).NotEmpty().EmailAddress();
        RuleFor(x => x.Phone).NotEmpty().Matches(@"^\d{3}-\d{3}-\d{4}$");
    }
}

The class inherits from AbstractValidator with the type of the class to be validated. The validation then takes place in the validator class in the constructor.

I have checked various conditions, whether the field is empty and meets a certain length and format. Practically, these conditions can be read well. Also, the use of regex is possible.

Inside the controller method, we still need to perform this validation.

[HttpPost]
public IActionResult CreateCustomer([FromBody] CustomerCreateRequest request)
{
  var validator = new CustomerCreateRequestValidator();
  var validationResult = validator.Validate(request);

  if (validationResult.IsValid == false)
  {
      return BadRequest(validationResult.Errors[0].ErrorMessage);
  }

  return Ok();
}

The example project can be found on GitHub.

However, only the incoming data should be validated [1]. The primary business logic should be covered by unit tests [1].

Best Practices

  • Name your validators after the data contracts they are validating [1]. This clarifies which validator should be used for a particular data contract and makes it easier to find and maintain the validator code.
  • Use the built-in validation rules provided by FluentValidation where possible. These are well-tested and can be easily reused.
  • Avoid duplicating validation logic across multiple validators. If multiple validators need to perform the same validation logic, extract that logic into a separate helper method that can be called from multiple validators.
  • Use the RuleFor method to declare validation rules for a specific property of a data contract. This makes it straightforward to which property a validation rule applies.
  • Use the When method to apply conditional validation rules. This allows you to change the validation logic based on the value of other properties in the data contract.

Domain Model vs. Data Contract

It is a best practice to separate the domain model from data contracts in an ASP.NET 6.0 project. The domain model represents the business logic and rules of the application, while data contracts are used to define the structure of data being passed between the client and server.

Keeping these two concerns separate allows for more flexibility and maintainability in the application. The domain model can evolve and change without affecting the data contracts. Changing or adding new data contracts does not affect the domain model.

This separation also makes it easier to unit test the domain logic, as it can be tested in isolation from the data contracts. Additionally, it can be easier to version the data contracts and handle backward compatibility.

Demo — Nested objects

Let’s assume our customers also has a field address, another class.

public class CustomerCreateRequest
{
    public string Name { get; set; }
    public string Email { get; set; }
    public string Phone { get; set; }
    
    public Address Address { get; set; }
}

public class Address
{
    public string Street { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string ZipCode { get; set; }
}

How do we validate this? For this, we have to go back to our validator.

public class CustomerCreateRequestValidator : AbstractValidator<CustomerCreateRequest>
{
    public CustomerCreateRequestValidator()
    {
        RuleFor(x => x.Name).NotEmpty().Length(0,100);
        RuleFor(x => x.Email).NotEmpty().EmailAddress();
        RuleFor(x => x.Phone).NotEmpty().Matches(@"^\d{3}-\d{3}-\d{4}$");
        
        RuleFor(x => x.Address).SetValidator(new AddressValidator());
    }
}

public class AddressValidator : AbstractValidator<Address>
{
    public AddressValidator()
    {
        RuleFor(x => x.Street).NotEmpty().Length(0,100);
        RuleFor(x => x.City).NotEmpty().Length(0,100);
        RuleFor(x => x.State).NotEmpty().Length(0,100);
        RuleFor(x => x.ZipCode).NotEmpty().Length(0,100);
    }
}

We create another validator and set it. We do this because otherwise, we would have to check multiple times if the Address is not null. To avoid this duplicating code logic, we set another validator.

Conclusion

In conclusion, FluentValidation is a powerful tool for validating data in an ASP.NET 6.0 project. By following best practices such as naming validators after the data contracts they are validating, using built-in validation rules, avoiding duplication of validation logic, and applying conditional validation, developers can create maintainable and efficient validation logic.

Additionally, it is essential to separate the domain model from the data contracts to achieve more flexibility, maintainability, and testability in the application.

The two simple demos in this post demonstrate how FluentValidation can be used to validate data and how to handle nested object validation. By following the best practices and understanding the difference between data contracts and domain models, developers can create robust and effective validation logic in their applications.

Make sure to check out my other Posts!

Want to connect and stay up-to-date on AI, tech, and .NET development? 

Follow me on Twitter and LinkedIn - I'm always happy to hear from you.

References

  1. FluentValidation Fundamentals By Vladimir Khorikov
Data Validation
Aspnetcore
Best Practices
Software Development
Software Engineering
Recommended from ReadMedium