Provides a very simple and easy-to-use data validation solution in ASP. By System.ComponentModel.DataAnnotations
providing a lot of validation rules (Required, stringlength, etc.). However, there are often such requirements, we want to be able to save the model validation rules to the data or XML files, rather than the code, the advantage is that we can easily modify the validation rules and error messages, to avoid the need to republish the site.
In this article, let's look at how you can configure validation of the model with the XML file through a custom modelvalidatorprovider.
Read the catalogue:
A simple review of the use of built-in MVC validation
Ii. analyzing the internal process of MVC validation
A city example, validation for ContactInfo
Iv. Concrete realization and application of Xmlmodelvalidatorprovider
One, a simple review of the use of built-in MVC validation
The following are typical MVC validation rules for Code and page presentation effects.
Second, analyzing the internal process of MVC validation
1. The actual verification is modelvalidator
When we like, after adding a variety of validation rules for the person class dataannotation attributes, the actual fencing to do validation is DataAnnotationsModelValidator类.
DataAnnotationsModelValidator
inherited from the abstract class modelvalidator, the implementation of the abstract method validate, In this method, the instance of all person is validated against the validation rules defined in the person class, and a collection of Modelvalidationresult is returned.
2. Modelvalidator is provided by modelvalidatorproviders
The modelvalidator used by MVC in the validation process is also provided by the Modelvalidatorproviders class, and Modelvalidatorproviders is an abstract class with an abstract method getvalidators.
The definition of the class is like this
namespace system.web.mvc{public abstract class Modelvalidatorprovider {public abstract ienumerable< Modelvalidator> getvalidators (Modelmetadata metadata, ControllerContext context);} }
In practice, MVC uses a Dataannotationsmodelvalidatorprovider class that inherits from Modelvalidatorprovider and implements the Getvalidators method.
3. The MVC validation process can exist in multipleModelValidatorProvider
MVC can have multiple modelvalidatorprovider at the same time, their effects can be superimposed. We can use the default Dataannotationsmodelvalidatorprovider to define validation rules based on attribute, You can also use our xmlmodelvalidatorprovider below to get validation rules from an XML file for validation.
Three, an example, for the validation of ContactInfo
The following ContactInfo class is what we use to do the actual verification, including some common typical authentication, Required, Email, URL, etc.
public class contactinfo{Public string FirstName {get; set;} public string Lastname{get;set;} public string Email{get;set;}
The following XML file, which defines the validation rules for the ContactInfo class, was previously written in the ContactInfo class, and now separates it and puts it into content\validation\rules\ The Contactinfo.xml file.
The value in the message here is just a key to the message, and the specific content of the message is placed in another XML file.
<?xml version= "1.0" encoding= "Utf-8"?><model> <validator property= "FirstName" type= "Required" message = "firstname_required"/> <validator property= "FirstName" type= "Stringlength" arg-int= "message=" FirstName_ Length "/> <validator property=" LastName "type=" Required "message=" lastname_required "/> <validator Proper Ty= "LastName" type= "stringlength" arg-int= "255" message= "Lastname_length"/> <validator property= "Email" type= " Required "message=" email_required "/> <validator property=" Email "type=" stringlength "arg-int=" 255 "message=" Email_length "/> <validator property=" Email "type=" RegularExpression "arg=" ^[\w-]+ (\.[ \w-]+) *@[\w-]+ (\.[ \w-]+) +$ "message=" email_regularexpression "/> <validator property=" Url "type=" stringlength "arg-int=" 255 " Message= "Url_length"/> <validator property= "Url" type= "RegularExpression" arg= "(/http)? (www\.)? \w+\. (com|net|edu|org) "message=" Url_regularexpression "/></model>
The message is stored in the Content\validation\messages\contactinfo.xml file
<?xml version= "1.0" encoding= "Utf-8"?><messages> <!--filed error message-- <message key= "firstname_required" text= "The Frist Name field is Required." ></message> <message key= "Firstname_length" text= "the field maximum Length is" ></message> <message key= "lastname_required" text= "The last Name field is Required." ></message> <message key= "Lastname_length" text= "the field maximum Length is 255" ></message> <message key= "email_required" text= "The Email field is Required." ></message> <message key= "Email_length" text= "the field maximum Length is 255" ></message> <message key= "email_regularexpression" text= "Invalid Email." ></message> <message key= "Url_length" text= "the field maximum Length is 255" ></message>
Iv. implementation and application of Xmlmodelvalidatorprovider
Here is the implementation code of our most important xmlmodelvalidatorprovider
public class xmlmodelvalidatorprovider:modelvalidatorprovider{//is used to save the existing test in System.ComponentModel.DataAnnotations Rules, that is, MVC's own required and other validation rules, because we just verify that the rule "source" is not the same, one is the code, one is XML, but the validation process is the same, so to reuse the already written validation in MVC. Private ReadOnly dictionary<string, type> _validatortypes; Private readonly String _xmlfolderpath = HttpContext.Current.Server.MapPath ("~//content//validation//rules"); Public Xmlmodelvalidatorprovider () {
_validatortypes = Assembly.Load ("System.ComponentModel.DataAnnotations"). GetTypes (). Where (t = t.issubclassof (typeof (Validationattribute))). ToDictionary (t = t.name, t = t); } #region Stolen from Dataannotationsmodelvalidatorprovider//delegate, converts Validationattribute into Dataannotationsmodelvalidator internal static Dataannotationsmodelvalidationfactory defaultattributefactory = (metadata, context, attribute) = new Dataannotationsmodelvalidator (metadata, context, attribute); Internal static Dictionary<type, dataannotationsmodelvalidationfactory> attributefactories = new Dictionary <type, dataannotationsmodelvalidationfactory> { { typeof (Rangeattribute), (Metadata, Contex T, attribute) = NE W Rangeattributeadapter (metadata, context, (Rangeattribute) attribute) }, { typeof (Regularexpressionattribute), (metadata, context, attribute) = New Regularexpressionattributeadapter (metadata, context, Regula Rexpressionattribute) attribute) }, {ty Peof (RequiredAttribute), (metadata, context, attribute) = New Requiredattributeadapter (metadata, context, (RequiredAttribute) attribute) }, { typeof (Stringlengthattribute), (metadata, context, attribute) = New String Lengthattributeadapter (metadata, context, (Stringlengthattribute) attribute) } }; #endregion//Overrides the Getvalidators method, which is obtained from the XML file. Based on the configuration of the XML, return the corresponding validator collection public override ienumerable<modelvalidator> getvalidators (Modelmetadata metadata, Co Ntrollercontext context) {var results = new list<modelvalidator> (); Whether the validation is for a property or model//(remember we can apply validation attributes to a proper Ty or model and same applies here as well) var ispropertyvalidation = metadata. Containertype! = NULL &&! String.IsNullOrEmpty (metadata. PropertyName); var Rulespath = String.Format ("{0}\\{1}.xml", _xmlfolderpath, Ispropertyvalidation ? Metadata. ContainerType.Name:metadata. Modeltype.name); var rules = file.exists (Rulespath)? Xelement.load (Rulespath). Xpathselectelements (String.Format ("./validator[@property = ' {0} ']", Ispropertyvalidation? Metadata. Propertyname:metadata. Modeltype.name)). ToList (): New list<xelement> (); produce a validator for each validation attribute we find foreach (var rule in rules) { Dataannotationsmodelvalidationfactory Factory; var validatortype = _validatortypes[string.concat (rule. Attribute ("type"). Value, "Attribute")]; if (! Attributefactories.trygetvalue (Validatortype, Out factory)) {factory = Defaultattributefa Ctory; } var validator = (Validationattribute) activator.createinstance (Validatortype, getvalidationargs (rule)); Validator. errormessage = rule. Attribute ("message")! = NULL &&! String.IsNullOrEmpty (rule. Attribute ("message"). Value)? Getvalidationmessage (ispropertyvalidation metadata. CoNtainerType.Name:metadata. Modeltype.name, rule. Attribute ("message"). Value): null; Results. ADD (Factory (metadata, context, validator)); } return results; } private String Getvalidationmessage (string model, string key) {return Messageprovider.getviewmode Lvalidationmessage (model, key); }//Read the arguments passed to the validation attribute and cast it their respective type. Private object[] Getvalidationargs (XElement rule) {var Validatorargs = rule. Attributes (). Where (A = a.name.tostring (). StartsWith ("Arg")); var args = new Object[validatorargs.count ()]; var i = 0; foreach (var arg in Validatorargs) {var argname = arg. Name.tostring (); var argvalue = arg. Value; if (!argname.contains ("-")) {args[i] = Argvalue; } else {var argtype = argname.split ('-') [1]; Switch (argtype) {case "int": args[i] = Int. Parse (Argvalue); Break Case "datetime": args[i] = DateTime.Parse (argvalue); Break Case "char": args[i] = Char.parse (argvalue); Break Case "Double": args[i] = Double.Parse (argvalue); Break Case "decimal": args[i] = Decimal.Parse (argvalue); Break Case "bool": args[i] = Boolean.Parse (argvalue); Break Default:args[i] = Argvalue; Break }}} return args; } }
Finally, in the Global.cs file, add Xmlmodelvalidatorprovider to the MVC modelvalidatorproviderscollection
MODELVALIDATORPROVIDERS.PROVIDERS.ADD (New Xmlmodelvalidatorprovider ());
MVC data validation principle and custom Modelvalidatorprovider implementation without compilation modify validation rules and error messages