{"id":53168,"date":"2020-08-24T08:00:27","date_gmt":"2020-08-24T06:00:27","guid":{"rendered":"https:\/\/code-maze.com\/?p=53168"},"modified":"2024-04-28T15:16:37","modified_gmt":"2024-04-28T13:16:37","slug":"fluentvalidation-in-aspnet","status":"publish","type":"post","link":"https:\/\/code-maze.com\/fluentvalidation-in-aspnet\/","title":{"rendered":"FluentValidation in ASP.NET Core"},"content":{"rendered":"<p><span style=\"font-weight: 400;\">In this article, we&#8217;re going to discuss the use of FluentValidation in ASP.NET Core.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Traditionally, most validation in .NET is done <a href=\"https:\/\/code-maze.com\/configuring-nonrelational-properties\/\" target=\"_blank\" rel=\"noopener noreferrer\">using Data Annotations<\/a>:<\/span><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public class SampleClass\r\n{\r\n    [Required]\r\n    public int Id { get; set; }\r\n\r\n\u00a0\u00a0\u00a0\u00a0[MaxLength(100)]\r\n    public string Name { get; set; }\r\n}<\/pre>\n<p><span style=\"font-weight: 400;\">There are a few issues with this approach:<\/span><\/p>\n<ul>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">Our model can get \u201cbloated\u201d<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">Extensibility is limited<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">Testing isn&#8217;t the nicest experience<\/span><\/li>\n<\/ul>\n<p><span style=\"font-weight: 400;\">To address some of these concerns, instead, we&#8217;re going to utilize a .NET library called FluentValidation to perform validation for our classes. We&#8217;re going to add validation to a <a href=\"https:\/\/code-maze.com\/net-core-series\/\" target=\"_blank\" rel=\"noopener noreferrer\">basic ASP.NET Core API<\/a>, but the techniques we&#8217;re going to follow can in fact be applied to any .NET application.<\/span><\/p>\n<div style=\"padding: 20px; border-left: 5px #dc2323 solid; display: block; margin-bottom: 20px; box-shadow: 1px 1px 5px 0px lightgrey;\">If you want to download the source code for this project, you can visit the<a href=\"https:\/\/github.com\/CodeMazeBlog\/fluent-validation-aspnetcore\" target=\"_blank\" rel=\"nofollow noopener noreferrer\"> FluentValidation in ASP.NET Core<\/a> repository<\/div>\n<p>Let&#8217;s move on.<\/p>\n<h2><a id=\"creating-a-simple-api\"><\/a>Creating a Simple ASP.NET Core API<\/h2>\n<p><span style=\"font-weight: 400;\">Let&#8217;s go ahead and create a File -&gt; New -&gt; ASP.NET Core 3.1 API using Visual Studio, accepting all the defaults.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400;\">At the end of the wizard, we&#8217;ll end up with the familiar \u201cWeather Forecast\u201d API structure:<\/span><\/p>\n<p><a href=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/06\/Screenshot_1-2.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-53189 size-full\" src=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/06\/Screenshot_1-2.jpg\" alt=\"ASP.NET Core FluentValidation Project structure\" width=\"274\" height=\"202\" \/><\/a><\/p>\n<p><span style=\"font-weight: 400;\">Now let&#8217;s hit CTRL-F5 to run our API and we should see some weather readings for the next few days:<\/span><\/p>\n<p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-title=\"\">[\r\n  {\r\n    &quot;date&quot;: &quot;2020-07-01T14:34:13.7180989+10:00&quot;,\r\n    &quot;temperatureC&quot;: 42,\r\n    &quot;temperatureF&quot;: 107,\r\n    &quot;summary&quot;: &quot;Bracing&quot;\r\n  },\r\n  {\r\n    &quot;date&quot;: &quot;2020-07-02T14:34:13.7181617+10:00&quot;,\r\n    &quot;temperatureC&quot;: 31,\r\n    &quot;temperatureF&quot;: 87,\r\n    &quot;summary&quot;: &quot;Freezing&quot;\r\n  },\r\n  {\r\n    &quot;date&quot;: &quot;2020-07-03T14:34:13.7181627+10:00&quot;,\r\n    &quot;temperatureC&quot;: 24,\r\n    &quot;temperatureF&quot;: 75,\r\n    &quot;summary&quot;: &quot;Scorching&quot;\r\n  },\r\n  {\r\n    &quot;date&quot;: &quot;2020-07-04T14:34:13.7181632+10:00&quot;,\r\n    &quot;temperatureC&quot;: -17,\r\n    &quot;temperatureF&quot;: 2,\r\n    &quot;summary&quot;: &quot;Hot&quot;\r\n  },\r\n  {\r\n    &quot;date&quot;: &quot;2020-07-05T14:34:13.7181636+10:00&quot;,\r\n    &quot;temperatureC&quot;: 52,\r\n    &quot;temperatureF&quot;: 125,\r\n    &quot;summary&quot;: &quot;Bracing&quot;\r\n  }\r\n]<\/pre><\/p>\n<p><span style=\"font-weight: 400;\">To demonstrate the use of validation, we&#8217;re going to add a new API method that allows us to add a new forecast.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">First, let&#8217;s open up <\/span><span style=\"font-weight: 400;\"><code>WeatherForecastController.cs<\/code>.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">We can see there&#8217;s a single method called <\/span><code><span style=\"font-weight: 400;\">Get()<\/span><\/code><span style=\"font-weight: 400;\"> which returns some weather forecasts (an array of <\/span><code><span style=\"font-weight: 400;\">WeatherForecast<\/span><\/code><span style=\"font-weight: 400;\">), which is the API called when we ran the application previously:<\/span><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">[HttpGet]\r\npublic IEnumerable&lt;WeatherForecast&gt; Get()\r\n{\r\n    var rng = new Random();\r\n    return Enumerable.Range(1, 5).Select(index =&gt; new WeatherForecast\r\n    {\r\n\t\tDate = DateTime.Now.AddDays(index),\r\n\t\tTemperatureC = rng.Next(-20, 55),\r\n\t\tSummary = Summaries[rng.Next(Summaries.Length)]\r\n    }).ToArray();\r\n}<\/pre>\n<p><span style=\"font-weight: 400;\">Now let&#8217;s add a method to the <code>WeatherForecastController<\/code> class:<\/span><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">[HttpPost]\r\npublic ActionResult Post([FromBody] WeatherForecast forecast)\r\n{\r\n    return Ok(\"Success!\");\r\n}\r\n<\/pre>\n<p><span style=\"font-weight: 400;\">This method accepts a <\/span><span style=\"font-weight: 400;\"><code>WeatherForecast<\/code> parameter<\/span><span style=\"font-weight: 400;\"> from the body of an HTTP POST request, and returns the string \u201cSuccess!\u201d.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Normally we&#8217;d do a few more useful things such as saving to a database and returning an HTTP 201 (Created) pointing to the location of our newly saved resource. However, for demonstration purposes let&#8217;s keep it nice and simple.\u00a0<\/span><\/p>\n<h3>Using Postman for API Testing<\/h3>\n<p><span style=\"font-weight: 400;\">Let&#8217;s now fire up Postman and confirm that our API works as expected.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">First, we&#8217;ll add a new request using the \u201cNew\u201d button in Postman:<\/span><\/p>\n<p><a href=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/06\/Untitled-2.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-53172 size-full\" src=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/06\/Untitled-2.png\" alt=\"Adding a new request in Postman\" width=\"308\" height=\"37\" srcset=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/06\/Untitled-2.png 308w, https:\/\/code-maze.com\/wp-content\/uploads\/2020\/06\/Untitled-2-300x36.png 300w\" sizes=\"auto, (max-width: 308px) 100vw, 308px\" \/><\/a><\/p>\n<p><span style=\"font-weight: 400;\">In the request, we&#8217;ll set the following values:<\/span><\/p>\n<ul>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">\u201cPOST\u201d as the HTTP Verb<\/span><\/li>\n<li style=\"font-weight: 400;\"><em><span style=\"font-weight: 400;\">http:\/\/localhost:61997\/weatherforecast<\/span><\/em><span style=\"font-weight: 400;\"> as the URL (change the port as necessary)<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">A header called \u201c<\/span><span style=\"font-weight: 400;\">Content-Type<\/span><span style=\"font-weight: 400;\">\u201d with the value \u201c<\/span><span style=\"font-weight: 400;\">application\/json<\/span><span style=\"font-weight: 400;\">\u201d<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">A body of type \u201cJSON\u201d, setting the \u201c<\/span><span style=\"font-weight: 400;\">TemperatureC<\/span><span style=\"font-weight: 400;\">\u201d field on our <\/span><span style=\"font-weight: 400;\">WeatherForecast <\/span><span style=\"font-weight: 400;\">model to the value <\/span><span style=\"font-weight: 400;\">6000<\/span><\/li>\n<\/ul>\n<p><span style=\"font-weight: 400;\">Then, let&#8217;s hit the \u201cSend\u201d button. If we did everything correctly, we should see our \u201cSuccess!\u201d text in the response:<\/span><\/p>\n<p><a href=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/06\/Screenshot_1.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-53187 size-full\" src=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/06\/Screenshot_1.jpg\" alt=\"Postman API response\" width=\"645\" height=\"397\" srcset=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/06\/Screenshot_1.jpg 645w, https:\/\/code-maze.com\/wp-content\/uploads\/2020\/06\/Screenshot_1-300x185.jpg 300w\" sizes=\"auto, (max-width: 645px) 100vw, 645px\" \/><\/a><\/p>\n<p><span style=\"font-weight: 400;\">Great!\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400;\">So we now have the ability to add new weather forecast. Notice however we&#8217;ve passed a value of <\/span><code><span style=\"font-weight: 400;\">6000 <\/span><\/code><span style=\"font-weight: 400;\">as the value for <\/span><code><span style=\"font-weight: 400;\">TemperatureC<\/span><\/code><span style=\"font-weight: 400;\">. This is hotter than the temperature of the Sun, so we probably shouldn&#8217;t allow this into our system for a weather forecast!<\/span><\/p>\n<p><span style=\"font-weight: 400;\">To put some rules around this, in the next section let&#8217;s add a simple validator to ensure that the value of <code>TemperatureC<\/code> cannot exceed <\/span><span style=\"font-weight: 400;\">100<\/span><span style=\"font-weight: 400;\">.<\/span><\/p>\n<h2><a id=\"adding-a-simple-validator\"><\/a>Adding a Simple FluentValidation Validator<\/h2>\n<p><span style=\"font-weight: 400;\">To add our simple validator, we first need to install FluentValidation in the package manager console:<\/span><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">PM&gt;&gt; install-package FluentValidation.AspNetCore<\/pre>\n<p><span style=\"font-weight: 400;\">The <\/span><code><span style=\"font-weight: 400;\">FluentValidation.AspNetCore<\/span><\/code><span style=\"font-weight: 400;\"> package installs both FluentValidation and also some extra functionality specific to ASP.NET Core that we&#8217;ll make use of a bit later.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Now, let&#8217;s go ahead and add a new validator with our rule directly in the <\/span><code><span style=\"font-weight: 400;\">WeatherForecast <\/span><\/code><span style=\"font-weight: 400;\">class:<\/span><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public class WeatherForecastValidator : AbstractValidator&lt;WeatherForecast&gt;\r\n{\r\n    public WeatherForecastValidator()\r\n    {\r\n        RuleFor(model =&gt; model.TemperatureC).LessThanOrEqualTo(100);\r\n    }\r\n}<\/pre>\n<p><span style=\"font-weight: 400;\">Let&#8217;s explain our code:<\/span><\/p>\n<ul>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">We create a class called <\/span><span style=\"font-weight: 400;\"><code>WeatherForecastValidator<\/code> <\/span><span style=\"font-weight: 400;\">that inherits from the <\/span><code><span style=\"font-weight: 400;\">AbstractValidator&lt;T&gt;<\/span><\/code><span style=\"font-weight: 400;\"> class, specifying the type <\/span><code><span style=\"font-weight: 400;\">WeatherForecast<\/span><\/code><span style=\"font-weight: 400;\">. This lets FluentValidation know that this validation is for the <\/span><span style=\"font-weight: 400;\"><code>WeatherForecast<\/code> <\/span><span style=\"font-weight: 400;\">class.<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">We can see a constructor specifying our rules. In this case, we define a single rule saying that the <\/span><code><span style=\"font-weight: 400;\">TemperatureC <\/span><\/code><span style=\"font-weight: 400;\">value needs to be &lt;= <code>100<\/code>.<\/span><\/li>\n<\/ul>\n<p><span style=\"font-weight: 400;\">We can place the validation class anywhere we like, but for the sake of simplicity let&#8217;s keep it in the same file.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">We can add as many rules as we like, chain validators, and even use custom validators, but we&#8217;ll focus on a single simple rule for now.\u00a0<\/span><\/p>\n<div style=\"padding: 20px; border-left: 5px #dc2323 solid; display: block; margin-bottom: 20px; box-shadow: 1px 1px 5px 0px lightgrey;\">If you want to dive even more into the FluentValidation logic, we strongly suggest you read the<a href=\"https:\/\/code-maze.com\/deep-dive-validators-fluentvalidation\/\" target=\"_blank\" rel=\"noopener noreferrer\"> Deep Dive with Different Validators with FluentValidation<\/a> article. There you can read in more detail about this topic.<\/div>\n<p><span style=\"font-weight: 400;\">In the next section, we&#8217;ll look at how we can write a simple unit test for our validator.<\/span><\/p>\n<h2><a id=\"testing-our-validator\"><\/a>Testing Our FluentValidation Validator<\/h2>\n<p><span style=\"font-weight: 400;\">One of the great things about FluentValidation is how easy it is to write unit tests. There is a nice set of built-in test helpers that make assertions a breeze and keep our tests nice and clean. To learn more about testing ASP.NET Core application, we strongly recommend reading our <a href=\"https:\/\/code-maze.com\/asp-net-core-mvc-testing\/\" target=\"_blank\" rel=\"noopener noreferrer\">ASP.NET Core Testing series<\/a>.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Let&#8217;s go ahead and set one up now.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400;\">First, we&#8217;ll add a new <\/span><b>xUnit Test Project (.NET Core)<\/b><span style=\"font-weight: 400;\"> to our solution:<\/span><\/p>\n<p><a href=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/06\/Screenshot_1-1.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-53188 size-full\" src=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/06\/Screenshot_1-1.jpg\" alt=\"Adding a new xUnit Test Project\" width=\"491\" height=\"94\" srcset=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/06\/Screenshot_1-1.jpg 491w, https:\/\/code-maze.com\/wp-content\/uploads\/2020\/06\/Screenshot_1-1-300x57.jpg 300w\" sizes=\"auto, (max-width: 491px) 100vw, 491px\" \/><\/a><\/p>\n<p><span style=\"font-weight: 400;\">Let&#8217;s rename <\/span><span style=\"font-weight: 400;\">UnitTest.cs<\/span><span style=\"font-weight: 400;\"> to <\/span><span style=\"font-weight: 400;\"><code>WeatherForecastValidatorTests.cs<\/code>. <\/span><span style=\"font-weight: 400;\">It&#8217;s good practice to name the test file matching the validator we are testing.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Next, let&#8217;s add a couple of references to the project. First, add a reference to our <\/span><span style=\"font-weight: 400;\"><code>WebApplication1<\/code> <\/span><span style=\"font-weight: 400;\">project:<\/span><\/p>\n<p><a href=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/06\/Screenshot_1-3.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-53190 size-full\" src=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/06\/Screenshot_1-3.jpg\" alt=\"Adding a reference to our project\" width=\"781\" height=\"179\" srcset=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/06\/Screenshot_1-3.jpg 781w, https:\/\/code-maze.com\/wp-content\/uploads\/2020\/06\/Screenshot_1-3-300x69.jpg 300w, https:\/\/code-maze.com\/wp-content\/uploads\/2020\/06\/Screenshot_1-3-768x176.jpg 768w\" sizes=\"auto, (max-width: 781px) 100vw, 781px\" \/><\/a><\/p>\n<p><span style=\"font-weight: 400;\">Now we are going to install a couple of packages into the tests project from the Package Manager Console.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">First the FluentValidation library:<\/span><\/p>\n<p><code><span style=\"font-weight: 400;\">PM&gt;&gt; install-package FluentValidation<\/span><\/code><\/p>\n<p><span style=\"font-weight: 400;\">Now the xUnit visual studio test runner:<\/span><\/p>\n<p><code><span style=\"font-weight: 400;\">PM&gt;&gt; install-package xunit.runner.visualstudio<\/span><\/code><\/p>\n<p><span style=\"font-weight: 400;\">Then let&#8217;s go ahead and open up the <\/span><span style=\"font-weight: 400;\"><code>WeatherForecastValidatorTests<\/code> <\/span><span style=\"font-weight: 400;\">class and add some tests.<\/span><\/p>\n<h3>Adding Test Methods<\/h3>\n<p><span style=\"font-weight: 400;\">First, we&#8217;ll add the following using statements:<\/span><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">using FluentValidation.TestHelper;\r\nusing WebApplication1;<\/pre>\n<p><span style=\"font-weight: 400;\">The first statement imports a set of test helpers that we can utilize, and the second adds a reference to our web application, so we can test the validator we wrote earlier.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Next, let&#8217;s add the following instance member to the <\/span><span style=\"font-weight: 400;\"><code>WeatherForecastValidatorTests<\/code> <\/span><span style=\"font-weight: 400;\">class:<\/span><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">private readonly WeatherForecastValidator _validator = new WeatherForecastValidator();<\/pre>\n<p><span style=\"font-weight: 400;\">This creates an instance of our validator so that we can use it for the tests we are about to write.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Now, we are going to add a method to test failing validation:<\/span><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">[Fact]\r\npublic void GivenAnInvalidTemperatureCValue_ShouldHaveValidationError()\r\n    =&gt; _validator.ShouldHaveValidationErrorFor(model =&gt; model.TemperatureC, 101);<\/pre>\n<p><span style=\"font-weight: 400;\">We are using an extension from the <code>FluentValidation.TestHelper<\/code> namespace, that allows us to do 3 things in 1 line:<\/span><\/p>\n<ol>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">Set a property to a value of our choosing (in this case, <code>101<\/code>)<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">Invoke the validator<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">Cause the test to pass\/fail based on the result<\/span><\/li>\n<\/ol>\n<p><span style=\"font-weight: 400;\">After that, let&#8217;s add a method to test successful validation:<\/span><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">[Theory]\r\n[InlineData(99)]\r\n[InlineData(100)]\r\npublic void GivenAValidTemperatureCValue_ShouldNotHaveValidationError(int temperatureC)\r\n\t=&gt; _validator.ShouldNotHaveValidationErrorFor(model =&gt; model.TemperatureC, temperatureC);<\/pre>\n<p><span style=\"font-weight: 400;\">This time we&#8217;re using the handy xUnit \u201ctheories\u201d, which allow us to pass multiple values to the test.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Now, if we jump over to the Test Explorer and run all our tests, we should see green lights across the board:<\/span><\/p>\n<p><a href=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/06\/Screenshot_1-4.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-53191 size-full\" src=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/06\/Screenshot_1-4.jpg\" alt=\"Test Explorer for FluentValidation testing actions\" width=\"604\" height=\"215\" srcset=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/06\/Screenshot_1-4.jpg 604w, https:\/\/code-maze.com\/wp-content\/uploads\/2020\/06\/Screenshot_1-4-300x107.jpg 300w\" sizes=\"auto, (max-width: 604px) 100vw, 604px\" \/><\/a><\/p>\n<p><span style=\"font-weight: 400;\">As you can see, FluentValidation makes it really easy to test our validation, allowing us to focus on testing individual properties. However, we can still test the entire validators for more complex scenarios.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Now that we know our validator works as expected, in the next section we are going to wire it up in our API.<\/span><\/p>\n<h2><a id=\"wiring-up-our-validator\"><\/a>Wiring up Our FluentValidation Validator<\/h2>\n<p><span style=\"font-weight: 400;\">Firstly, we need to tell ASP.NET Core MVC that we&#8217;d like to use FluentValidation and to look for validators in our assembly when performing the model binding.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">To do that, we need to add a single line to the <\/span><span style=\"font-weight: 400;\"><code>ConfigureServices<\/code> <\/span><span style=\"font-weight: 400;\">in <\/span><code><span style=\"font-weight: 400;\">Startup.cs<\/span><\/code> in .NET 5 or previous versions:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public void ConfigureServices(IServiceCollection services)\r\n{\r\n    services.AddControllers()\r\n            .AddFluentValidation(fv =&gt; fv.RegisterValidatorsFromAssemblyContaining&lt;WeatherForecastValidator&gt;());\r\n}<\/pre>\n<p><strong>In .NET 6 and later, we have to modify the Program class:<\/strong><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">builder.Services.AddControllers()\r\n    .AddFluentValidation(fv =&gt; fv.RegisterValidatorsFromAssemblyContaining&lt;WeatherForecastValidator&gt;());<\/pre>\n<p><span style=\"font-weight: 400;\">This wires up the FluentValidation middleware with ASP.NET Core MVC, and tells FluentValidation to look for any validators in the assembly containing our <\/span><code><span style=\"font-weight: 400;\">WeatherForecastValidator<\/span><\/code><span style=\"font-weight: 400;\">. In other words, look for any validators in our API project.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Let&#8217;s confirm everything is working by hitting Send again in Postman:<\/span><\/p>\n<p><a href=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/06\/Screenshot_1-6.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-53197 size-full\" src=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/06\/Screenshot_1-6.jpg\" alt=\"Postman API response showing FluentValidation validation error\" width=\"624\" height=\"553\" srcset=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/06\/Screenshot_1-6.jpg 624w, https:\/\/code-maze.com\/wp-content\/uploads\/2020\/06\/Screenshot_1-6-300x266.jpg 300w\" sizes=\"auto, (max-width: 624px) 100vw, 624px\" \/><\/a><\/p>\n<p><span style=\"font-weight: 400;\">As expected, our validation is firing correctly, and we&#8217;re now returning an error back to the user.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400;\">What&#8217;s great about this approach is we don&#8217;t need to explicitly check the <\/span><span style=\"font-weight: 400;\">ModelState <\/span><span style=\"font-weight: 400;\">in our controller to see if the input is valid. The FluentValidation ASP.NET middleware will automatically find our validator, and if validation fails it will prepare the ModelState and our action will return a 400 response as we can see above.\u00a0<\/span><\/p>\n<h2><a id=\"conclusion\"><\/a>Conclusion<\/h2>\n<p><span style=\"font-weight: 400;\">FluentValidation provides a great alternative to Data Annotations in order to validate our models. As we&#8217;ve seen, the validation rules are easy to read, easy to test, and enable great separation of concerns keeping our controllers lightweight.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">In this article, we&#8217;ve only really touched the tip of the iceberg. FluentValidation also has a bunch of other great features such as:<\/span><\/p>\n<ul>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">Collection validators, where we can invoke our validator N times when we have a sequence of items<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">A large number of built-in validators (for example, validating credit card numbers, email addresses, and enums)<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">Ability to write custom validators and pull in dependencies, for example, if we need to do validation via our database<\/span><\/li>\n<\/ul>\n<p><span style=\"font-weight: 400;\">Happy coding!<\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this article, we&#8217;re going to discuss the use of FluentValidation in ASP.NET Core. Traditionally, most validation in .NET is done using Data Annotations: public class SampleClass { [Required] public int Id { get; set; } \u00a0\u00a0\u00a0\u00a0[MaxLength(100)] public string Name { get; set; } } There are a few issues with this approach: Our model [&hellip;]<\/p>\n","protected":false},"author":3,"featured_media":54156,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_et_pb_use_builder":"","_et_pb_old_content":"","_et_gb_content_width":"","footnotes":""},"categories":[12],"tags":[712,79,711],"class_list":["post-53168","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-csharp","tag-api-validation","tag-asp-net-core","tag-fluentvalidation","et-has-post-format-content","et_post_format-et-post-format-standard"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v24.7 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>How to Use FluentValidation in ASP.NET Core<\/title>\n<meta name=\"description\" content=\"Learn how to make use of FluentValidation in an ASP.NET Core application, to validate user input and make our applications easier to maintain and test.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/code-maze.com\/fluentvalidation-in-aspnet\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"How to Use FluentValidation in ASP.NET Core\" \/>\n<meta property=\"og:description\" content=\"Learn how to make use of FluentValidation in an ASP.NET Core application, to validate user input and make our applications easier to maintain and test.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/code-maze.com\/fluentvalidation-in-aspnet\/\" \/>\n<meta property=\"og:site_name\" content=\"Code Maze\" \/>\n<meta property=\"article:published_time\" content=\"2020-08-24T06:00:27+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-04-28T13:16:37+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/07\/fluentvalidators-aspnet.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1100\" \/>\n\t<meta property=\"og:image:height\" content=\"620\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Marinko Spasojevi\u0107\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@https:\/\/twitter.com\/CodeMazeBlog\" \/>\n<meta name=\"twitter:site\" content=\"@CodeMazeBlog\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Marinko Spasojevi\u0107\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"8 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":[\"Article\",\"BlogPosting\"],\"@id\":\"https:\/\/code-maze.com\/fluentvalidation-in-aspnet\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/code-maze.com\/fluentvalidation-in-aspnet\/\"},\"author\":{\"name\":\"Marinko Spasojevi\u0107\",\"@id\":\"https:\/\/code-maze.com\/#\/schema\/person\/d6fa06e66820968d19b39fb63cff2533\"},\"headline\":\"FluentValidation in ASP.NET Core\",\"datePublished\":\"2020-08-24T06:00:27+00:00\",\"dateModified\":\"2024-04-28T13:16:37+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/code-maze.com\/fluentvalidation-in-aspnet\/\"},\"wordCount\":1429,\"commentCount\":6,\"publisher\":{\"@id\":\"https:\/\/code-maze.com\/#organization\"},\"image\":{\"@id\":\"https:\/\/code-maze.com\/fluentvalidation-in-aspnet\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/07\/fluentvalidators-aspnet.png\",\"keywords\":[\"api validation\",\"asp.net core\",\"FluentValidation\"],\"articleSection\":[\"C#\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/code-maze.com\/fluentvalidation-in-aspnet\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/code-maze.com\/fluentvalidation-in-aspnet\/\",\"url\":\"https:\/\/code-maze.com\/fluentvalidation-in-aspnet\/\",\"name\":\"How to Use FluentValidation in ASP.NET Core\",\"isPartOf\":{\"@id\":\"https:\/\/code-maze.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/code-maze.com\/fluentvalidation-in-aspnet\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/code-maze.com\/fluentvalidation-in-aspnet\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/07\/fluentvalidators-aspnet.png\",\"datePublished\":\"2020-08-24T06:00:27+00:00\",\"dateModified\":\"2024-04-28T13:16:37+00:00\",\"description\":\"Learn how to make use of FluentValidation in an ASP.NET Core application, to validate user input and make our applications easier to maintain and test.\",\"breadcrumb\":{\"@id\":\"https:\/\/code-maze.com\/fluentvalidation-in-aspnet\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/code-maze.com\/fluentvalidation-in-aspnet\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/code-maze.com\/fluentvalidation-in-aspnet\/#primaryimage\",\"url\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/07\/fluentvalidators-aspnet.png\",\"contentUrl\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/07\/fluentvalidators-aspnet.png\",\"width\":1100,\"height\":620,\"caption\":\"fluentvalidators aspnet\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/code-maze.com\/fluentvalidation-in-aspnet\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/code-maze.com\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"FluentValidation in ASP.NET Core\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/code-maze.com\/#website\",\"url\":\"https:\/\/code-maze.com\/\",\"name\":\"Code Maze\",\"description\":\"Learn. Code. Succeed.\",\"publisher\":{\"@id\":\"https:\/\/code-maze.com\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/code-maze.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/code-maze.com\/#organization\",\"name\":\"Code Maze\",\"url\":\"https:\/\/code-maze.com\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/code-maze.com\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez.png\",\"contentUrl\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez.png\",\"width\":3511,\"height\":3510,\"caption\":\"Code Maze\"},\"image\":{\"@id\":\"https:\/\/code-maze.com\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/x.com\/CodeMazeBlog\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/code-maze.com\/#\/schema\/person\/d6fa06e66820968d19b39fb63cff2533\",\"name\":\"Marinko Spasojevi\u0107\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/code-maze.com\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/marinko-1x1-3-150x150.jpg\",\"contentUrl\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/marinko-1x1-3-150x150.jpg\",\"caption\":\"Marinko Spasojevi\u0107\"},\"description\":\"Hi, my name is Marinko Spasojevic. Currently, I work as a full-time .NET developer and my passion is web application development. Just getting something to work is not enough for me. To make it just how I like it, it must be readable, reusable, and easy to maintain. Prior to being an author on the CodeMaze blog, I had been working as a professor of Computer Science for several years. So, sharing knowledge while working as a full-time developer comes naturally to me.\",\"sameAs\":[\"https:\/\/www.linkedin.com\/in\/marinko-spasojevic\/\",\"https:\/\/x.com\/https:\/\/twitter.com\/CodeMazeBlog\"],\"url\":\"https:\/\/code-maze.com\/author\/marinko\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"How to Use FluentValidation in ASP.NET Core","description":"Learn how to make use of FluentValidation in an ASP.NET Core application, to validate user input and make our applications easier to maintain and test.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/code-maze.com\/fluentvalidation-in-aspnet\/","og_locale":"en_US","og_type":"article","og_title":"How to Use FluentValidation in ASP.NET Core","og_description":"Learn how to make use of FluentValidation in an ASP.NET Core application, to validate user input and make our applications easier to maintain and test.","og_url":"https:\/\/code-maze.com\/fluentvalidation-in-aspnet\/","og_site_name":"Code Maze","article_published_time":"2020-08-24T06:00:27+00:00","article_modified_time":"2024-04-28T13:16:37+00:00","og_image":[{"width":1100,"height":620,"url":"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/07\/fluentvalidators-aspnet.png","type":"image\/png"}],"author":"Marinko Spasojevi\u0107","twitter_card":"summary_large_image","twitter_creator":"@https:\/\/twitter.com\/CodeMazeBlog","twitter_site":"@CodeMazeBlog","twitter_misc":{"Written by":"Marinko Spasojevi\u0107","Est. reading time":"8 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":["Article","BlogPosting"],"@id":"https:\/\/code-maze.com\/fluentvalidation-in-aspnet\/#article","isPartOf":{"@id":"https:\/\/code-maze.com\/fluentvalidation-in-aspnet\/"},"author":{"name":"Marinko Spasojevi\u0107","@id":"https:\/\/code-maze.com\/#\/schema\/person\/d6fa06e66820968d19b39fb63cff2533"},"headline":"FluentValidation in ASP.NET Core","datePublished":"2020-08-24T06:00:27+00:00","dateModified":"2024-04-28T13:16:37+00:00","mainEntityOfPage":{"@id":"https:\/\/code-maze.com\/fluentvalidation-in-aspnet\/"},"wordCount":1429,"commentCount":6,"publisher":{"@id":"https:\/\/code-maze.com\/#organization"},"image":{"@id":"https:\/\/code-maze.com\/fluentvalidation-in-aspnet\/#primaryimage"},"thumbnailUrl":"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/07\/fluentvalidators-aspnet.png","keywords":["api validation","asp.net core","FluentValidation"],"articleSection":["C#"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/code-maze.com\/fluentvalidation-in-aspnet\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/code-maze.com\/fluentvalidation-in-aspnet\/","url":"https:\/\/code-maze.com\/fluentvalidation-in-aspnet\/","name":"How to Use FluentValidation in ASP.NET Core","isPartOf":{"@id":"https:\/\/code-maze.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/code-maze.com\/fluentvalidation-in-aspnet\/#primaryimage"},"image":{"@id":"https:\/\/code-maze.com\/fluentvalidation-in-aspnet\/#primaryimage"},"thumbnailUrl":"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/07\/fluentvalidators-aspnet.png","datePublished":"2020-08-24T06:00:27+00:00","dateModified":"2024-04-28T13:16:37+00:00","description":"Learn how to make use of FluentValidation in an ASP.NET Core application, to validate user input and make our applications easier to maintain and test.","breadcrumb":{"@id":"https:\/\/code-maze.com\/fluentvalidation-in-aspnet\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/code-maze.com\/fluentvalidation-in-aspnet\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/code-maze.com\/fluentvalidation-in-aspnet\/#primaryimage","url":"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/07\/fluentvalidators-aspnet.png","contentUrl":"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/07\/fluentvalidators-aspnet.png","width":1100,"height":620,"caption":"fluentvalidators aspnet"},{"@type":"BreadcrumbList","@id":"https:\/\/code-maze.com\/fluentvalidation-in-aspnet\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/code-maze.com\/"},{"@type":"ListItem","position":2,"name":"FluentValidation in ASP.NET Core"}]},{"@type":"WebSite","@id":"https:\/\/code-maze.com\/#website","url":"https:\/\/code-maze.com\/","name":"Code Maze","description":"Learn. Code. Succeed.","publisher":{"@id":"https:\/\/code-maze.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/code-maze.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/code-maze.com\/#organization","name":"Code Maze","url":"https:\/\/code-maze.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/code-maze.com\/#\/schema\/logo\/image\/","url":"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez.png","contentUrl":"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez.png","width":3511,"height":3510,"caption":"Code Maze"},"image":{"@id":"https:\/\/code-maze.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/x.com\/CodeMazeBlog"]},{"@type":"Person","@id":"https:\/\/code-maze.com\/#\/schema\/person\/d6fa06e66820968d19b39fb63cff2533","name":"Marinko Spasojevi\u0107","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/code-maze.com\/#\/schema\/person\/image\/","url":"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/marinko-1x1-3-150x150.jpg","contentUrl":"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/marinko-1x1-3-150x150.jpg","caption":"Marinko Spasojevi\u0107"},"description":"Hi, my name is Marinko Spasojevic. Currently, I work as a full-time .NET developer and my passion is web application development. Just getting something to work is not enough for me. To make it just how I like it, it must be readable, reusable, and easy to maintain. Prior to being an author on the CodeMaze blog, I had been working as a professor of Computer Science for several years. So, sharing knowledge while working as a full-time developer comes naturally to me.","sameAs":["https:\/\/www.linkedin.com\/in\/marinko-spasojevic\/","https:\/\/x.com\/https:\/\/twitter.com\/CodeMazeBlog"],"url":"https:\/\/code-maze.com\/author\/marinko\/"}]}},"_links":{"self":[{"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/posts\/53168","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/comments?post=53168"}],"version-history":[{"count":6,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/posts\/53168\/revisions"}],"predecessor-version":[{"id":116657,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/posts\/53168\/revisions\/116657"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/media\/54156"}],"wp:attachment":[{"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/media?parent=53168"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/categories?post=53168"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/tags?post=53168"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}