Model validation is to check that data received from an HTTP request is compliant at the time of model binding to ensure the validity of the data, and to provide information to help users correct the error when they receive invalid data.
Explicit model validation
The most straightforward way to validate data is to validate the received data in the action method, taking the following model as an example:
public class Appointment {Public string ClientName {get; set;} Public DateTime Date {get; set;} public bool termsaccepted {get; set;} }
We require clientname cannot be empty; Date date cannot be earlier than current date, format of date can be used in Web. config <globalization culture= "en-US" uiculture= "Enus"/> To specify otherwise, the default time zone format for the server is used; termsaccepted must be true. We collect data in the makebooking.cshtml view:
Validate the requested data directly in the action method:
Modelstate.isvalidfield () checks whether the model binder successfully binds the "Date" property if the data is not lawfully used modelstate.addmodelerror () to add an error message. If there is no error, modelstate.isvalid=true, we can continue normal operation, otherwise return to the data input interface. Html. The editfor () Help function checks if Modelstate contains errors for the current property, and if an error adds a CSS class input-validation-error to the generated element, the default Input-validation-error class is defined in the ~/ In Content/site.css:
The effect is to make the border of the input control red and the background pink to prompt the user for an error to occur. If you write your own Html helper function to support validation errors, you can refer to how System.Mvc.Web.Html.InputExtensions's source code is implemented.
Some browsers, such as Chrome and Firefox, ignore the CSS properties that are applied to the checkboxes, and can be resolved using the custom template described earlier:
@model bool? @if (ViewData.ModelMetadata.IsNullableValueType) { @Html. dropdownlistfor (M = = m, new SelectList (new [] {"Not Set "True", "False"}, Model)} else { modelstate state = viewdata.modelstate[viewdata.modelmetadata.propertyname];< C3/>bool value = Model?? false; if (state! = null && state. Errors.Count > 0) { <div class= "Input-validation-error" style= "Float:left" > @Html. CheckBox ("", Value) </div> } else { @Html. CheckBox ("", Value) }}
This defines a custom template of type bool, which wraps a checkbox with a DIV tag, checks the current property for errors from Modelstate, and adds a CSS class to the DIV tag with an error when the error occurs.
Show validation Messages
In addition to the CSS style hint error, we can display the error message added to Modelstate in the view to the user:
@model modelvalidation.models.appointment@{viewbag.title = "Make A Booking";}
The html.validationsummary () Help function lists the error messages in the Modelstate as a list and displays them to the user. ValidationSummary has several overloaded forms:
Overloaded form |
Description |
Html.validationsummary () |
Summary shows all validation errors |
Html.validationsummary (BOOL) |
If the bool parameter is =true, only the model level error is displayed, otherwise all validation errors are displayed |
Html.validationsummary (String) |
Displays the string given by strings before all error messages |
Html.validationsummary (bool, string) |
Same as Html.validationsummary (BOOL), which displays the string given in front of the error message only |
The so-called model level error, in fact, is to use Modelstate.addmodelerror () to add an error message when the first parameter that represents the error attribute is left blank, for example:
... if (Modelstate.isvalidfield ("ClientName") && Modelstate.isvalidfield ("Date") && appt. ClientName = = "Joe" && appt. Date.dayofweek = = dayofweek.monday) {modelstate.addmodelerror ("", "Joe cannot book appointments on Mondays");} ...
In addition to Html.validationsummary (), we can display the error message immediately next to the input control:
@model modelvalidation.models.appointment@{ viewbag.title = "Make A Booking";}
Html.validationmessagefor () displays the corresponding error message when the property has an error, and to avoid repeating the display in the rollup message, use the true parameter to call Html.validationsummary (true).
Model Binding Timing ValidationThe default model binder Defaultmodelbinder is built in to validate data in bindings, such as when we enter a non-date format to the Date property, the binder gives "the value ' xxx ' is not valid for date." The error message. We can reload some of the defaultmodelbinder methods to add useful information:
Method |
Description |
Features that are implemented by default |
ommodelupdated |
Called when the binder attempts to assign values to all properties of a model object |
Add error messages to modelstate based on validation rule validation data given by model metadata |
SetProperty |
Called when the Binder view assigns a value to a property of a model object |
If the model property cannot be null but there is no data to bind, add "the <name> field is required" message to modelstate, if there is data but processing error such as type conversion failed to add "the value <value > is isn't valid for <name> "message to Modelstate |
Using metadata to specify validation rules
More often we don't need to reload the default model binder because we can more easily use metadata to add validation rules to the data model:
The required and range two features are used, which indicates that the data is required, the latter specifies a range of available values, ErrorMessage is the prompt message when the error occurs, and if not specified, the default message in the table above is used. The available validation features are:
attribute |
Example |
Description |
Compare |
[Compare ("Myotherproperty")] |
Two properties must have the same value, such as when we ask the user to repeat the two-time email address Use |
range |
[Range]] the |
property value must be within a specified range of values, and you can use the maximum minimum value of a numeric type, such as Int. MinValue, Int. MaxValue |
regularexpression |
[RegularExpression ("pattern")] |
String value must be With regular expressions, default case sensitive, you can use the (? i) modifier to turn off case sensitivity, such as [RegularExpression ("(? i) Mypattern")] |
Required |
[ Required] |
property value must be non-empty or not just a space, if all spaces can be allowed [Required (allowemptystrings = True)] |
stringlengt H |
[stringlength]] |
string length cannot exceed the given maximum length, or you can specify a minimum length: [Stringlength (minimumlength=2)] | /tr>
The above example does not use the required attribute to verify the termsaccepted of the bool type, because Editfor () gives more than one hidden INPUT element in the render checkbox. Even if we don't check the checkbox, the returned results are still valued. Using range looks awkward, but we can create custom validation attribute classes to improve:
public class Mustbetrueattribute:validationattribute {public override bool IsValid (object value) { return Valu E is bool && (bool) value; } }
Here to verify that the input data is of type bool and true, using this custom validation feature is simple:
.. [Mustbetrue (errormessage= "You must accept the terms")] public bool termsaccepted {get; set;} ...
In addition to extending the custom attributes from Validationattribute, we can extend directly from the built-in validation feature:
public class Futuredateattribute:requiredattribute {public override bool IsValid (object value) { return base. IsValid (value) && ((DateTime) value) > DateTime.Now; } }
This validates the feature extension from require, and then makes additional checks after calling the base class for validation.
The validation features above are for the individual properties of the model, and we can also create custom validation attributes for the entire model:
public class Nojoeonmondaysattribute:validationattribute {public Nojoeonmondaysattribute () { errormessage = "Joe cannot book appointments on Mondays"; } public override bool IsValid (object value) { Appointment app = value as appointment; if (app = = NULL | | string. IsNullOrEmpty (app. ClientName) | | App. Date = = null) { //We don't have a model of the right type to validate, or we don't have //The values for the Cli Entname and Date properties we require return true; } else { return! ( App. ClientName = = "Joe" && app. Date.dayofweek = = Dayofweek.monday);}}}
Here we check the customer name and the agreed date, do not allow the customer name Joe in Monday to make an appointment, we can apply this feature to the entire model class:
With these validation rule attributes, the action method of the Controller class can be greatly simplified to:
... [HttpPost] Public ViewResult makebooking (Appointment appt) { if (modelstate.isvalid) { //statements to store new Appointmen T in a //repository would go to here in a real project return View ("completed", appt); } else { return view ( ); } } ...
Self-validating model
Another model validation is to create a self-validating model class for the Model class implementation Ivalidatableobject interface:
Using system;using system.collections.generic;using system.componentmodel.dataannotations;using Modelvalidation.infrastructure;namespace modelvalidation.models{public class Appointment:ivalidatableobject { public string ClientName {get; set;} [DataType (Datatype.date)] public DateTime Date {get; set;} public bool termsaccepted {get; set;} Public ienumerable<validationresult> Validate (Validationcontext validationcontext) {List<valid ationresult> errors = new list<validationresult> (); if (string. IsNullOrEmpty (ClientName)) {errors. ADD (New Validationresult ("Please enter your name")); } if (DateTime.Now > Date) {errors. ADD (New Validationresult ("Please enter a date on the future"); } if (errors. Count = = 0 && ClientName = = "Joe" && Date.dayofweek = = dayofweek.monday) {errors. ADD (New Validationresult ("Joe cannot book appointments on Mondays")); } if (! termsaccepted) {errors. ADD (New Validationresult ("You must accept the terms"); } return errors; } }}
The model binder calls validate () when attempting to assign a value to a model object, and returns the result as a list of errors, which we can do in one place for all data validation.
Client Authentication
The above is the data submitted to the server after the validation, the client we can pass the script before the data submitted to the server to verify, MVC support "unobtrusive client-side validation", Unobtrusive means adding a specific HTML tag when the HTML tag is printed, and the Java Script Validation Library of MVC uses these specialized features for data validation. To use client-side validation first needs to be enabled in Web. config:
The above two settings must all be true, We can use htmlhelper.clientvalidationenabled and htmlhelper.unobtrusivejavascriptenabled in the Razor code block to configure whether client-side validation is used for a single view. We must also ensure that the following script files are added to the view or layout file:
- /scripts/jquery-1.7.1.min.js
- /scripts/jquery.validate.min.js
- /scripts/jquery.validate.unobtrusive.min.js
You can see that client-side validation is still dependent on jquery. When client-side validation is enabled, the built-in validation features that we add to the model class, such as Requried, Stringlength, can work directly, and the Java script gives an error when the data validation error occurs. Specifically, editfor () These template helper functions output some additional features when client-side validation is enabled, such as the ClientName property above:
The jquery validation function looks for data-val=true elements for validation,data-val-<xxx> is a specific validation rule, such as data-val-length and data-val-required here. The validation rules specified by the metadata can be used either on the client or server side, and it is very convenient for us, and the server-side data validation is still valid even if the Java script is disabled on the client.
Remote Authentication
Remote authentication is a compromise between client authentication and server-side validation, in which the client validates data to the server through an AJAX request, and a typical scenario can be authentication of the user name, allowing the user to continue the subsequent input after the user name verification is successful. Using remote authentication starts by defining an action method for validation from the controller:
... public jsonresult validatedate (string Date) { DateTime parseddate; if (! Datetime.tryparse (date, out parseddate)) { return Json ("Please enter a valid date (MM/DD/YYYY)", jsonrequestbehavior.allowget); } else if (DateTime.Now > Parseddate) { return Json ("Please enter a date on the future", Jsonrequestbehavior.allo WGet); } else { return Json (True, jsonrequestbehavior.allowget); } } ...
Verify that the action method must have a parameter that has the same name as the field to be validated, and it is considered that the date is a string type. Model binding If the exception cannot be converted from the request data to a date type, Remote Authentication cannot display the exception information on the client is silently discarded, so we typically use the string type to explicitly convert the data type inside the validation method. The validation method returns a Jsonresult object that validates successfully we encapsulated true, does not successfully encapsulate the error message, regardless of the result we use the Jsonrequestbehavior.allowget identity validation result can be obtained through a GET request.
With the remote validation action, we need to add remote validation attributes to the corresponding model class properties:
public class Appointment { [Required] [Stringlength (Ten, minimumlength = 3)] public string ClientName {get; s Et } [DataType (datatype.date)] [Remote ("Validatedate", "Home")] public DateTime Date { Get Set } public bool termsaccepted {get; set;} }
In the Remote authentication feature, specify the controller name to use for authentication and the JavaScript validation library for ACTION,MVC to request and validate the URL that is generated by this build. Remote authentication takes effect when the user submits the form for the first time, as well as every subsequent edit of the data, such as a remote validation of each keystroke, which we need to consider when bandwidth is limited.
The above is a summary of the contents of the fourth edition of the Apress Pro ASP. NET MVC 4, as described in the original http://www.apress.com/9781430242369.
ASP. NET MVC 4 (10) Model validation