Validation in ASP .NET Core 3.1
Tags: dotnet, webdev, csharp
Published: 2020-06-15 19:49:47

---
title: Validation in ASP .NET Core 3.1
published: true
date: 2020-06-15 14:00:00 UTC
tags: dotnet, webdev, csharp 
canonical_url: https://wakeupandcode.com/validation-in-asp-net-core-3-1/
---

![](https://wakeupandcode.com/wp-content/uploads/2020/01/aspnetcore-az-banner.png)

This is the twenty-second of a new [series of posts](https://wakeupandcode.com/aspnetcore/#aspnetcore2020) on ASP .NET Core 3.1 for 2020. In this series, we’ll cover 26 topics over a span of 26 weeks from January through June 2020, titled  **ASP .NET Core A-Z!**  To differentiate from the [2019 series](https://wakeupandcode.com/aspnetcore/#aspnetcore2019), the 2020 series will mostly focus on a growing single codebase ([NetLearner!](https://wakeupandcode.com/netlearner-on-asp-net-core-3-1/)) instead of new unrelated code snippets week.

Previous post:

- [Unit Testing in ASP .NET Core 3.1](https://wakeupandcode.com/unit-testing-in-asp-net-core-3-1/)

**NetLearner on GitHub** :

- Repository: [https://github.com/shahedc/NetLearnerApp](https://github.com/shahedc/NetLearnerApp)
- v0.22-alpha release: [https://github.com/shahedc/NetLearnerApp/releases/tag/v0.22-alpha](https://github.com/shahedc/NetLearnerApp/releases/tag/v0.22-alpha)

# In this Article:

- [V is for Validation](#V)
- [Validation Attributes](#attr)
- [Server-Side Validation](#server)
- [Client-Side Validation](#client)
- [Client to Server with Remote Validation](#remote)
- [Custom Attributes](#custom)
- [References](#refs)

# V is for Validation

To build upon a previous post on [Forms and Fields in ASP .NET Core](https://wakeupandcode.com/forms-and-fields-in-asp-net-core-3-1/), this post covers Validation in ASP .NET Core. When a user submits form field values, proper validation can help build a more user-friendly and secure web application. Instead of coding each view/page individually, you can simply use server-side attributes in your models/viewmodels.

**NOTE** : As of ASP .NET Core 2.2, validation may be skipped automatically if ASP .NET Core decides that validation is not needed. According to the [“What’s New” release notes](https://docs.microsoft.com/en-us/aspnet/core/release-notes/aspnetcore-2.2?view=aspnetcore-2.2#validation-performance), this includes primitive collections (e.g. a byte[] array or a Dictonary<string, string> key-value pair collection)

![](https://wakeupandcode.com/wp-content/uploads/2020/05/validation-diagram-1024x427.png)<figcaption>Validation in ASP .NET Core</figcaption>

# Validation Attributes

To implement model validation with [Attributes], you will typically use Data Annotations from the [System.ComponentModel.DataAnnotations](https://docs.microsoft.com/en-us/dotnet/api/system.componentmodel.dataannotations) namespace. The list of attribute does go beyond just validation functionality though. For example, the DataType attribute takes a datatype parameter, used for inferring the data type and used for displaying the field on a view/page (but does not provide validation for the field).

Common attributes include the following

- **Range** : lets you specify min-max values, inclusive of min and max
- **RegularExpression** : useful for pattern recognition, e.g. phone numbers, zip/postal codes
- **Required** : indicates that a field is required
- **StringLength** : sets the maximum length for the string entered
- **MinLength** : sets the minimum length of an array or string data

From the sample code, here is an example from the [LearningResource model class](https://github.com/shahedc/NetLearnerApp/blob/master/src/NetLearner.SharedLib/Models/LearningResource.cs) in [NetLearner](https://wakeupandcode.com/netlearner-on-asp-net-core-3-1/)‘s shared library:

```
public class **LearningResource** { public int Id { get; set; } **[DisplayName("Resource")] [Required] [StringLength(100)]** public string Name { get; set; } **[DisplayName("URL")] [Required] [StringLength(255)] [DataType(DataType.Url)]** public string Url { get; set; } public int ResourceListId { get; set; } **[DisplayName("In List")]** public ResourceList ResourceList { get; set; } **[DisplayName("Feed Url")]** public string ContentFeedUrl { get; set; } public List<LearningResourceTopicTag> LearningResourceTopicTags { get; set; }}
```

From the above code, you can see that:

- The value for  **Name** is a required string, needs to be less than 100 characters
- The value for  **Url** is a required string, needs to be less than 255 characters 
- The value for  **ContentFeedUrl**  can be left blank, but has to be less than 255 characters.
- When the  **DataType**  is provided (e.g. **DataType.Url** , Currency, Date, etc), the field is displayed appropriately in the browser, with the proper formatting
- For numeric values, you can also use the **[Range(x,y)]** attribute, where x and y sets the minimum and maximum values allowed for the number

Here’s what it looks like in a browser when validation fails:

![](https://wakeupandcode.com/wp-content/uploads/2020/06/validation-create-errors-1024x660.png)<figcaption>Validation errors in NetLearner.MVC</figcaption>

![](https://wakeupandcode.com/wp-content/uploads/2020/06/validation-create-errors-pages-1024x599.png)<figcaption> Validation errors in NetLearner.Pages</figcaption>

![](https://wakeupandcode.com/wp-content/uploads/2020/06/validation-create-errors-blazor-1024x582.png)<figcaption> Validation errors in NetLearner.Blazor</figcaption>

The validation rules make it easier for the user to correct their entries before submitting the form.

- In the above scenario, the “is required” messages are displayed directly in the browser through client-side validation. 
- For field-length restrictions, the client-side form will automatically prevent the entry of string values longer than the maximum threshold 
- If a user attempts to circumvent any validation requirements on the client-side, the server-side validation will automatically catch them. 

In the **MVC** and **Razor Pages** web projects, the validation messages are displayed with the help of <div> and <span> elements, using asp-validation-summary and asp-validation-for.

**NetLearner.Mvc** : [/Views/LearningResources/Create.cshtml](https://github.com/shahedc/NetLearnerApp/blob/master/src/NetLearner.Mvc/Views/LearningResources/Create.cshtml)

```
<div **asp-validation-summary** ="ModelOnly" class="text-danger"></div> <div class="form-group"> <label asp-for="Name" class="control-label"></label> <input asp-for="Name" class="form-control" /> <span **asp-validation-for** ="Name" class="text-danger"></span> </div>
```

**NetLearner.Pages** : [/Pages/LearningResources/Create.cshtml](https://github.com/shahedc/NetLearnerApp/blob/master/src/NetLearner.Pages/Pages/LearningResources/Create.cshtml)

```
<div **asp-validation-summary** ="ModelOnly" class="text-danger"></div> <div class="form-group"> <label asp-for="LearningResource.Name" class="control-label"></label> <input asp-for="LearningResource.Name" class="form-control" /> <span **asp-validation-for** ="LearningResource.Name" class="text-danger"></span> </div>
```

In the **Blazor** project, the “The DataAnnotationsValidator component attaches validation support using data annotations” and “The ValidationSummary component summarizes validation messages”.

**NetLearner.Blazor** : [/Pages/ResourceDetail.razor](https://github.com/shahedc/NetLearnerApp/blob/master/src/NetLearner.Blazor/Pages/ResourceDetail.razor)

```
<EditForm Model="@LearningResourceObject" OnValidSubmit="@HandleValidSubmit"> < **DataAnnotationsValidator** /> < **ValidationSummary** />
```

For more information on Blazor validation, check out the official documentation at:

- Blazor Forms and Validation: [https://docs.microsoft.com/en-us/aspnet/core/blazor/forms-validation?view=aspnetcore-3.1](https://docs.microsoft.com/en-us/aspnet/core/blazor/forms-validation?view=aspnetcore-3.1) 

# Server-Side Validation

Validation occurs before an MVC controller action (or equivalent handler method for Razor Pages) takes over. As a result, you should check to see if the validation has passed before continuing next steps.

e.g. in an MVC controller

```
[**HttpPost**][**ValidateAntiForgeryToken**]public async Task<IActionResult> **Create** (...){ if ( **ModelState.IsValid** ) { // ... return RedirectToAction(nameof(Index)); } return View(...);}
```

e.g. in a Razor Page’s handler code:

```
public async Task<IActionResult> **OnPostAsync** (){ if (! **ModelState.IsValid** ) { return Page(); } //... return RedirectToPage(...);}
```

Note that  **ModelState**. **IsValid**  is checked in both the  **Create** () action method of an MVC Controller or the  **OnPostAsync** () handler method of a Razor Page’s handler code. If  **IsValid**  is true, perform actions as desired. If false, reload the current view/page as is.

In the Blazor example, the **OnValidSubmit** event is triggered by < **EditForm** > when a form is submitted, e.g.

```
< **EditForm** Model="@SomeModel" **OnValidSubmit** ="@ **HandleValidSubmit**">
```

The method name specified refers to a C# method that handles the form submission when valid.

```
private async void **HandleValidSubmit** (){ ...}
```

# Client-Side Validation

It goes without saying that you should always have server-side validation. All the client-side validation in the world won’t prevent a malicious user from sending a GET/POST request to your form’s endpoint. Cross-site request forgery in the [Form tag helper](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/working-with-forms#the-form-tag-helper) does provide a certain level of protection, but you still need server-side validation. That being said, client-side validation helps to catch the problem before your server receives the request, while providing a better user experience.

When you create a new ASP .NET Core project using one of the built-in templates for MVC or Razor Pages, you should see a shared partial view called [\_ValidationScriptsPartial.cshtml](https://github.com/shahedc/NetLearnerApp/blob/master/src/NetLearner.Mvc/Views/Shared/_ValidationScriptsPartial.cshtml). This partial view should include references to [jQuery unobtrusive validation](https://github.com/aspnet/jquery-validation-unobtrusive), as shown below:

```
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
```

If you create a scaffolded controller with views/pages, you should see the following reference at the bottom of your page or view.

e.g. at the bottom of [Create.cshtml](https://github.com/shahedc/NetLearnerApp/blob/master/src/NetLearner.Mvc/Views/LearningResources/Create.cshtml) view

```
@section Scripts { @{await Html.RenderPartialAsync(" **\_ValidationScriptsPartial**");}}
```

e.g. at the bottom of the [Create.cshtml](https://github.com/shahedc/NetLearnerApp/blob/master/src/NetLearner.Pages/Pages/LearningResources/Create.cshtml) page

```
@section Scripts { @{await Html.RenderPartialAsync(" **\_ValidationScriptsPartial**");}}
```

Note that the syntax is identical whether it’s an MVC view or a Razor page. If you ever need to disable client-side validation for some reason, that can be accomplished in different ways, whether it’s for an MVC view or a Razor page. (Blazor makes use of the aforementioned EditForm element in ASP .NET Core to include built-in validation, with the ability to track whether a submitted form is valid or invalid.)

From the official [docs](https://docs.microsoft.com/en-us/aspnet/core/mvc/models/validation#disable-client-side-validation), the following code should be used within the  **ConfigureServices** () method of your Startup.cs class, to set  **ClientValidationEnabled**  to false in your HTMLHelperOptions configuration.

```
services. **AddMvc** (). **AddViewOptions** (options =>{ if (\_env.IsDevelopment()) { options.HtmlHelperOptions. **ClientValidationEnabled** = false; }});
```

Also mentioned in the official docs, the following code can be used for your Razor Pages, within the  **ConfigureServices** () method of your Startup.cs class.

```
services.Configure< **HtmlHelperOptions** >(o => o. **ClientValidationEnabled** = false);
```

# Client to Server with Remote Validation

If you need to call a server-side method while performing client-side validation, you can use the [**Remote**] attribute on a model property. You would then pass it the name of a server-side action method which returns an  **IActionResult ** with a true boolean result for a valid field. This [**Remote**] attribute is available in the Microsoft.AspNetCore.Mvc namespace, from the [Microsoft.AspNetCore.Mvc.ViewFeatures](https://www.nuget.org/packages/Microsoft.AspNetCore.Mvc.ViewFeatures) NuGet package.

The model property would look something like this:

```
[**Remote** (action: " **MyActionMethod**", controller: " **MyControllerName**")]public string **MyProperty** { get; set; }
```

In the controller class, (e.g.  **MyControllerName** ), you would define an action method with the name specified in the [**Remote**] attribute parameters, e.g.  **MyActionMethod. **

```
[**AcceptVerbs** ("Get", "Post")]public IActionResult **MyActionMethod** (...){ if (TestForFailureHere()) { return **Json** ("Invalid Error Message"); } return **Json(true)**;}
```

You may notice that if the validation fails, the controller action method returns a JSON response with an appropriate error message in a string. Instead of a text string, you can also use a false, null, or undefined value to indicate an invalid result. If validation has passed, you would use **Json(true)** to indicate that the validation has passed.

_So, when would you actually use something like this?_ Any scenario where a selection/entry needs to be validated by the server can provide a better user experience by providing a result as the user is typing, instead of waiting for a form submission. For example: imagine that a user is buying online tickets for an event, and selecting a seat number displayed on a seating chart. The selected seat could then be displayed in an input field and then sent back to the server to determine whether the seat is still available or not.

# Custom Attributes

In addition to all of the above, you can simply build your own custom attributes. If you take a look at the classes for the built-in attributes, e.g. [RequiredAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.componentmodel.dataannotations.requiredattribute), you will notice that they also extend the same parent class:

- System.ComponentModel.DataAnnotations.ValidationAttribute

You can do the same thing with your custom attribute’s class definition:

```
public class **MyCustomAttribute** : ValidationAttribute { // ...}
```

The parent class [ValidationAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.componentmodel.dataannotations.validationattribute), has a virtual  **IsValid** () method that you can override to return whether validation has been calculated successfully (or not).

```
public class **MyCustomAttribute** : **ValidationAttribute** { // ... protected override ValidationResult **IsValid** ( object value, ValidationContext validationContext) { if (TestForFailureHere()) { return new **ValidationResult** ("Invalid Error Message"); } return **ValidationResult.Success** ; }}
```

You may notice that if the validation fails, the **IsValid(**) method returns a  **ValidationResult** () with an appropriate error message in a string. If validation has passed, you would return  **ValidationResult.Success**  to indicate that the validation has passed.

# References

- Add validation to an ASP.NET Core MVC app: [https://docs.microsoft.com/en-us/aspnet/core/tutorials/first-mvc-app/validation](https://docs.microsoft.com/en-us/aspnet/core/tutorials/first-mvc-app/validation)
- Model validation in ASP.NET Core MVC and Razor Pages: [https://docs.microsoft.com/en-us/aspnet/core/mvc/models/validation](https://docs.microsoft.com/en-us/aspnet/core/mvc/models/validation)
- System.ComponentModel.DataAnnotations Namespace: [https://docs.microsoft.com/en-us/dotnet/api/system.componentmodel.dataannotations](https://docs.microsoft.com/en-us/dotnet/api/system.componentmodel.dataannotations)
- ValidationAttribute Class (System.ComponentModel.DataAnnotations): [https://docs.microsoft.com/en-us/dotnet/api/system.componentmodel.dataannotations.validationattribute](https://docs.microsoft.com/en-us/dotnet/api/system.componentmodel.dataannotations.validationattribute)
- Blazor Forms and Validation: [https://docs.microsoft.com/en-us/aspnet/core/blazor/forms-validation?view=aspnetcore-3.1](https://docs.microsoft.com/en-us/aspnet/core/blazor/forms-validation?view=aspnetcore-3.1)