--- title: Model validation in ASP.NET Core MVC author: rick-anderson description: Learn about model validation in ASP.NET Core MVC and Razor Pages. ms.author: riande ms.custom: mvc ms.date: 04/06/2019 monikerRange: '>= aspnetcore-2.1' uid: mvc/models/validation --- # Model validation in ASP.NET Core MVC and Razor Pages This article explains how to validate user input in an ASP.NET Core MVC or Razor Pages app. [View or download sample code](https://github.com/aspnet/AspNetCore.Docs/tree/master/aspnetcore/mvc/models/validation/sample) ([how to download](xref:index#how-to-download-a-sample)). ## Model state Model state represents errors that come from two subsystems: model binding and model validation. Errors that originate from [model binding](model-binding.md) are generally data conversion errors (for example, an "x" is entered in a field that expects an integer). Model validation occurs after model binding and reports errors where the data doesn't conform to business rules (for example, a 0 is entered in a field that expects a rating between 1 and 5). Both model binding and validation occur before the execution of a controller action or a Razor Pages handler method. For web apps, it's the app's responsibility to inspect `ModelState.IsValid` and react appropriately. Web apps typically redisplay the page with an error message: [!code-csharp[](validation/sample_snapshot/Create.cshtml.cs?name=snippet&highlight=3-6)] Web API controllers don't have to check `ModelState.IsValid` if they have the `[ApiController]` attribute. In that case, an automatic HTTP 400 response containing issue details is returned when model state is invalid. For more information, see [Automatic HTTP 400 responses](xref:web-api/index#automatic-http-400-responses). ## Rerun validation Validation is automatic, but you might want to repeat it manually. For example, you might compute a value for a property and want to rerun validation after setting the property to the computed value. To rerun validation, call the `TryValidateModel` method, as shown here: [!code-csharp[](validation/sample/Controllers/MoviesController.cs?name=snippet_TryValidateModel&highlight=11)] ## Validation attributes Validation attributes let you specify validation rules for model properties. The following example from [the sample app](https://github.com/aspnet/AspNetCore.Docs/tree/master/aspnetcore/mvc/models/validation/sample) shows a model class that is annotated with validation attributes. The `[ClassicMovie]` attribute is a custom validation attribute and the others are built-in. (Not shown is `[ClassicMovie2]`, which shows an alternative way to implement a custom attribute.) [!code-csharp[](validation/sample/Models/Movie.cs?name=snippet_ModelClass)] ## Built-in attributes Here are some of the built-in validation attributes: * `[CreditCard]`: Validates that the property has a credit card format. * `[Compare]`: Validates that two properties in a model match. * `[EmailAddress]`: Validates that the property has an email format. * `[Phone]`: Validates that the property has a telephone number format. * `[Range]`: Validates that the property value falls within a specified range. * `[RegularExpression]`: Validates that the property value matches a specified regular expression. * `[Required]`: Validates that the field is not null. See [[Required] attribute](#required-attribute) for details about this attribute's behavior. * `[StringLength]`: Validates that a string property value doesn't exceed a specified length limit. * `[Url]`: Validates that the property has a URL format. * `[Remote]`: Validates input on the client by calling an action method on the server. See [[Remote] attribute](#remote-attribute) for details about this attribute's behavior. A complete list of validation attributes can be found in the [System.ComponentModel.DataAnnotations](xref:System.ComponentModel.DataAnnotations) namespace. ### Error messages Validation attributes let you specify the error message to be displayed for invalid input. For example: ```csharp [StringLength(8, ErrorMessage = "Name length can't be more than 8.")] ``` Internally, the attributes call `String.Format` with a placeholder for the field name and sometimes additional placeholders. For example: ```csharp [StringLength(8, ErrorMessage = "{0} length must be between {2} and {1}.", MinimumLength = 6)] ``` When applied to a `Name` property, the error message created by the preceding code would be "Name length must be between 6 and 8.". To find out which parameters are passed to `String.Format` for a particular attribute's error message, see the [DataAnnotations source code](https://github.com/dotnet/corefx/tree/master/src/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations). ## [Required] attribute By default, the validation system treats non-nullable parameters or properties as if they had a `[Required]` attribute. [Value types](/dotnet/csharp/language-reference/keywords/value-types) such as `decimal` and `int` are non-nullable. ### [Required] validation on the server On the server, a required value is considered missing if the property is null. A non-nullable field is always valid, and the [Required] attribute's error message is never displayed. However, model binding for a non-nullable property may fail, resulting in an error message such as `The value '' is invalid`. To specify a custom error message for server-side validation of non-nullable types, you have the following options: * Make the field nullable (for example, `decimal?` instead of `decimal`). [Nullable\](/dotnet/csharp/programming-guide/nullable-types/) value types are treated like standard nullable types. * Specify the default error message to be used by model binding, as shown in the following example: [!code-csharp[](validation/sample/Startup.cs?name=snippet_MaxModelValidationErrors&highlight=4-5)] For more information about model binding errors that you can set default messages for, see . ### [Required] validation on the client Non-nullable types and strings are handled differently on the client compared to the server. On the client: * A value is considered present only if input is entered for it. Therefore, client-side validation handles non-nullable types the same as nullable types. * Whitespace in a string field is considered valid input by the jQuery Validation [required](https://jqueryvalidation.org/required-method/) method. Server-side validation considers a required string field invalid if only whitespace is entered. As noted earlier, non-nullable types are treated as though they had a `[Required]` attribute. That means you get client-side validation even if you don't apply the `[Required]` attribute. But if you don't use the attribute, you get a default error message. To specify a custom error message, use the attribute. ## [Remote] attribute The `[Remote]` attribute implements client-side validation that requires calling a method on the server to determine whether field input is valid. For example, the app may need to verify whether a user name is already in use. To implement remote validation: 1. Create an action method for JavaScript to call. The jQuery Validate [remote](https://jqueryvalidation.org/remote-method/) method expects a JSON response: * `"true"` means the input data is valid. * `"false"`, `undefined`, or `null` means the input is invalid. Display the default error message. * Any other string means the input is invalid. Display the string as a custom error message. Here's an example of an action method that returns a custom error message: [!code-csharp[](validation/sample/Controllers/UsersController.cs?name=snippet_VerifyEmail)] 1. In the model class, annotate the property with a `[Remote]` attribute that points to the validation action method, as shown in the following example: [!code-csharp[](validation/sample/Models/User.cs?name=snippet_UserEmailProperty)] The `[Remote]` attribute is in the `Microsoft.AspNetCore.Mvc` namespace. Install the [Microsoft.AspNetCore.Mvc.ViewFeatures](https://www.nuget.org/packages/Microsoft.AspNetCore.Mvc.ViewFeatures) NuGet package if you're not using the `Microsoft.AspNetCore.App` or `Microsoft.AspNetCore.All` metapackage. ### Additional fields The `AdditionalFields` property of the `[Remote]` attribute lets you validate combinations of fields against data on the server. For example, if the `User` model had `FirstName` and `LastName` properties, you might want to verify that no existing users already have that pair of names. The following example shows how to use `AdditionalFields`: [!code-csharp[](validation/sample/Models/User.cs?name=snippet_UserNameProperties)] `AdditionalFields` could be set explicitly to the strings `"FirstName"` and `"LastName"`, but using the [`nameof`](/dotnet/csharp/language-reference/keywords/nameof) operator simplifies later refactoring. The action method for this validation must accept both first name and last name arguments: [!code-csharp[](validation/sample/Controllers/UsersController.cs?name=snippet_VerifyName)] When the user enters a first or last name, JavaScript makes a remote call to see if that pair of names has been taken. To validate two or more additional fields, provide them as a comma-delimited list. For example, to add a `MiddleName` property to the model, set the `[Remote]` attribute as shown in the following example: ```cs [Remote(action: "VerifyName", controller: "Users", AdditionalFields = nameof(FirstName) + "," + nameof(LastName))] public string MiddleName { get; set; } ``` `AdditionalFields`, like all attribute arguments, must be a constant expression. Therefore, don't use an [interpolated string](/dotnet/csharp/language-reference/keywords/interpolated-strings) or call to initialize `AdditionalFields`. ## Alternatives to built-in attributes If you need validation not provided by built-in attributes, you can: * [Create custom attributes](#custom-attributes). * [Implement IValidatableObject](#ivalidatableobject). ## Custom attributes For scenarios that the built-in validation attributes don't handle, you can create custom validation attributes. Create a class that inherits from , and override the method. The `IsValid` method accepts an object named *value*, which is the input to be validated. An overload also accepts a `ValidationContext` object, which provides additional information, such as the model instance created by model binding. The following example validates that the release date for a movie in the *Classic* genre isn't later than a specified year. The `[ClassicMovie2]` attribute checks the genre first and continues only if it's *Classic*. For movies identified as classics, it checks the release date to make sure it's not later than the limit passed to the attribute constructor.) [!code-csharp[](validation/sample/Attributes/ClassicMovieAttribute.cs?name=snippet_ClassicMovieAttribute)] The `movie` variable in the preceding example represents a `Movie` object that contains the data from the form submission. The `IsValid` method checks the date and genre. Upon successful validation, `IsValid` returns a `ValidationResult.Success` code. When validation fails, a `ValidationResult` with an error message is returned. ## IValidatableObject The preceding example works only with `Movie` types. Another option for class-level validation is to implement `IValidatableObject` in the model class, as shown in the following example: [!code-csharp[](validation/sample/Models/MovieIValidatable.cs?name=snippet&highlight=1,26-34)] ## Top-level node validation Top-level nodes include: * Action parameters * Controller properties * Page handler parameters * Page model properties Model-bound top-level nodes are validated in addition to validating model properties. In the following example from the sample app, the `VerifyPhone` method uses the to validate the `phone` action parameter: [!code-csharp[](validation/sample/Controllers/UsersController.cs?name=snippet_VerifyPhone)] Top-level nodes can use with validation attributes. In the following example from the sample app, the `CheckAge` method specifies that the `age` parameter must be bound from the query string when the form is submitted: [!code-csharp[](validation/sample/Controllers/UsersController.cs?name=snippet_CheckAge)] In the Check Age page (*CheckAge.cshtml*), there are two forms. The first form submits an `Age` value of `99` as a query string: `https://localhost:5001/Users/CheckAge?Age=99`. When a properly formatted `age` parameter from the query string is submitted, the form validates. The second form on the Check Age page submits the `Age` value in the body of the request, and validation fails. Binding fails because the `age` parameter must come from a query string. When running with `CompatibilityVersion.Version_2_1` or later, top-level node validation is enabled by default. Otherwise, top-level node validation is disabled. The default option can be overridden by setting the property in (`Startup.ConfigureServices`), as shown here: [!code-csharp[](validation/sample_snapshot/Startup.cs?name=snippet_AddMvc&highlight=4)] ## Maximum errors Validation stops when the maximum number of errors is reached (200 by default). You can configure this number with the following code in `Startup.ConfigureServices`: [!code-csharp[](validation/sample/Startup.cs?name=snippet_MaxModelValidationErrors&highlight=3)] ## Maximum recursion traverses the object graph of the model being validated. For models that are very deep or are infinitely recursive, validation may result in stack overflow. [MvcOptions.MaxValidationDepth](xref:Microsoft.AspNetCore.Mvc.MvcOptions.MaxValidationDepth) provides a way to stop validation early if the visitor recursion exceeds a configured depth. The default value of `MvcOptions.MaxValidationDepth` is 200 when running with `CompatibilityVersion.Version_2_2` or later. For earlier versions, the value is null, which means no depth constraint. ## Automatic short-circuit Validation is automatically short-circuited (skipped) if the model graph doesn't require validation. Objects that the runtime skips validation for include collections of primitives (such as `byte[]`, `string[]`, `Dictionary`) and complex object graphs that don't have any validators. ## Disable validation To disable validation: 1. Create an implementation of `IObjectModelValidator` that doesn't mark any fields as invalid. [!code-csharp[](validation/sample/Attributes/NullObjectModelValidator.cs?name=snippet_DisableValidation)] 1. Add the following code to `Startup.ConfigureServices` to replace the default `IObjectModelValidator` implementation in the dependency injection container. [!code-csharp[](validation/sample/Startup.cs?name=snippet_DisableValidation)] You might still see model state errors that originate from model binding. ## Client-side validation Client-side validation prevents submission until the form is valid. The Submit button runs JavaScript that either submits the form or displays error messages. Client-side validation avoids an unnecessary round trip to the server when there are input errors on a form. The following script references in *_Layout.cshtml* and *_ValidationScriptsPartial.cshtml* support client-side validation: [!code-cshtml[](validation/sample/Views/Shared/_Layout.cshtml?name=snippet_ScriptTag)] [!code-cshtml[](validation/sample/Views/Shared/_ValidationScriptsPartial.cshtml?name=snippet_ScriptTags)] The [jQuery Unobtrusive Validation](https://github.com/aspnet/jquery-validation-unobtrusive) script is a custom Microsoft front-end library that builds on the popular [jQuery Validate](https://jqueryvalidation.org/) plugin. Without jQuery Unobtrusive Validation, you would have to code the same validation logic in two places: once in the server-side validation attributes on model properties, and then again in client-side scripts. Instead, [Tag Helpers](xref:mvc/views/tag-helpers/intro) and [HTML helpers](xref:mvc/views/overview) use the validation attributes and type metadata from model properties to render HTML 5 `data-` attributes for the form elements that need validation. jQuery Unobtrusive Validation parses the `data-` attributes and passes the logic to jQuery Validate, effectively "copying" the server-side validation logic to the client. You can display validation errors on the client using tag helpers as shown here: [!code-cshtml[](validation/sample/Views/Movies/Create.cshtml?name=snippet_ReleaseDate&highlight=4-5)] The preceding tag helpers render the following HTML. ```html

Movie

``` Notice that the `data-` attributes in the HTML output correspond to the validation attributes for the `ReleaseDate` property. The `data-val-required` attribute contains an error message to display if the user doesn't fill in the release date field. jQuery Unobtrusive Validation passes this value to the jQuery Validate [`required()`](https://jqueryvalidation.org/required-method/) method, which then displays that message in the accompanying **\** element. Data type validation is based on the .NET type of a property, unless that is overridden by a `[DataType]` attribute. Browsers have their own default error messages, but the jQuery Validation Unobtrusive Validation package can override those messages. `[DataType]` attributes and subclasses such as `[EmailAddress]` let you specify the error message. ### Add Validation to Dynamic Forms jQuery Unobtrusive Validation passes validation logic and parameters to jQuery Validate when the page first loads. Therefore, validation doesn't work automatically on dynamically generated forms. To enable validation, tell jQuery Unobtrusive Validation to parse the dynamic form immediately after you create it. For example, the following code sets up client-side validation on a form added via AJAX. ```js $.get({ url: "https://url/that/returns/a/form", dataType: "html", error: function(jqXHR, textStatus, errorThrown) { alert(textStatus + ": Couldn't add form. " + errorThrown); }, success: function(newFormHTML) { var container = document.getElementById("form-container"); container.insertAdjacentHTML("beforeend", newFormHTML); var forms = container.getElementsByTagName("form"); var newForm = forms[forms.length - 1]; $.validator.unobtrusive.parse(newForm); } }) ``` The `$.validator.unobtrusive.parse()` method accepts a jQuery selector for its one argument. This method tells jQuery Unobtrusive Validation to parse the `data-` attributes of forms within that selector. The values of those attributes are then passed to the jQuery Validate plugin. ### Add Validation to Dynamic Controls The `$.validator.unobtrusive.parse()` method works on an entire form, not on individual dynamically generated controls, such as `` and ` ``` As noted earlier, [Tag Helpers](xref:mvc/views/tag-helpers/intro) and [HTML helpers](xref:mvc/views/overview) use information from validation attributes to render `data-` attributes. There are two options for writing code that results in the creation of custom `data-` HTML attributes: * Create a class that derives from `AttributeAdapterBase` and a class that implements `IValidationAttributeAdapterProvider`, and register your attribute and its adapter in DI. This method follows the [single responsibility principal](https://wikipedia.org/wiki/Single_responsibility_principle) in that server-related and client-related validation code is in separate classes. The adapter also has the advantage that since it is registered in DI, other services in DI are available to it if needed. * Implement `IClientModelValidator` in your `ValidationAttribute` class. This method might be appropriate if the attribute doesn't do any server-side validation and doesn't need any services from DI. ### AttributeAdapter for client-side validation This method of rendering `data-` attributes in HTML is used by the `ClassicMovie` attribute in the sample app. To add client validation by using this method: 1. Create an attribute adapter class for the custom validation attribute. Derive the class from [AttributeAdapterBase\](/dotnet/api/microsoft.aspnetcore.mvc.dataannotations.attributeadapterbase-1?view=aspnetcore-2.2). Create an `AddValidation` method that adds `data-` attributes to the rendered output, as shown in this example: [!code-csharp[](validation/sample/Attributes/ClassicMovieAttributeAdapter.cs?name=snippet_ClassicMovieAttributeAdapter)] 1. Create an adapter provider class that implements . In the `GetAttributeAdapter` method pass in the custom attribute to the adapter's constructor, as shown in this example: [!code-csharp[](validation/sample/Attributes/CustomValidationAttributeAdapterProvider.cs?name=snippet_CustomValidationAttributeAdapterProvider)] 1. Register the adapter provider for DI in `Startup.ConfigureServices`: [!code-csharp[](validation/sample/Startup.cs?name=snippet_MaxModelValidationErrors&highlight=8-10)] ### IClientModelValidator for client-side validation This method of rendering `data-` attributes in HTML is used by the `ClassicMovie2` attribute in the sample app. To add client validation by using this method: * In the custom validation attribute, implement the `IClientModelValidator` interface and create an `AddValidation` method. In the `AddValidation` method, add `data-` attributes for validation, as shown in the following example: [!code-csharp[](validation/sample/Attributes/ClassicMovie2Attribute.cs?name=snippet_ClassicMovie2Attribute)] ## Disable client-side validation The following code disables client validation in MVC views: [!code-csharp[](validation/sample_snapshot/Startup2.cs?name=snippet_DisableClientValidation)] And in Razor Pages: [!code-csharp[](validation/sample_snapshot/Startup3.cs?name=snippet_DisableClientValidation)] Another option for disabling client validation is to comment out the reference to `_ValidationScriptsPartial` in your *.cshtml* file. ## Additional resources * [System.ComponentModel.DataAnnotations namespace](xref:System.ComponentModel.DataAnnotations) * [Model Binding](model-binding.md)