Recently in the study of the ASP. NET MVC model, it is found that Defaultmodelbinder has a disadvantage, that is, the browser request parameters can not be customized, the original idea is to set the attributes of the Entity model properties (Attribute), Then, by obtaining the attribute value of the set, we study the long-time MVC source and find that the BindProperty method can be used to achieve the desired goal by rewriting the Defaultmodelbinder.
There is a custom model binding attribute in ASP. Custommodelbinderattribute, which is intended to be done by overriding the Custommodelbinderattribute to the entity properties, as follows:
[AttributeUsageAttribute (attributetargets.class| Attributetargets.struct| attributetargets.enum| attributetargets.interface| Attributetargets.parameter, AllowMultiple = False, inherited = False)]public abstract class Custommodelbinderattribute: Attribute
However, since Custommodelbinderattribute does not support setting attributes on properties, it has to inherit the Attribute class to write a feature, the code is as follows:
<summary>///Represents an attribute that invokes a custom model binder. </summary> [AttributeUsage (validtargets, AllowMultiple = False, inherited = False)] public class Propertym Odelbinderattribute:attribute {//<summary>///Specify the application element that this attribute can apply attributes to. </summary> Internal const AttributeTargets Validtargets = Attributetargets.field | Attributetargets.enum | Attributetargets.property | Attributetargets.parameter; <summary>//Declaration property name. </summary> private String _propertyname = String. Empty; <summary>////Gets or sets the property alias. </summary> public string PropertyName {get {return _propertyname;} }///<summary>//Use the specified property alias. </summary>//<param name= "propertyname" > Specified property alias. </param> public Propertymodelbinderattribute (String propertyname) {_propertyname = prOpertyname; }///<summary>///Retrieve the associated model binder: </summary>///<returns> references to objects that implement the System.Web.Mvc.IModelBinder interface. </returns> public Imodelbinder Getbinder () {return new Propertymodelbinder (); }
This allows you to set an alias on the properties of the entity model.
<summary>/// represents a City filter entity Object model. // </summary> [Modelbinder (typeof (Propertymodelbinder))] public class Cityfilteringmodel:baseentitymodel { //<summary>///To get or set the city English name. // </summary> public string Cityenglishname {get; set;} <summary> ///Get or set the city number. // </summary> [Propertymodelbinder ("CID")] public int Cityid {get; set;} <summary> ///Get or set the city name. // </summary> [Propertymodelbinder ("CNAME")] public string CityName {get; set;} }
Finally, the BindProperty and SetProperty methods of overriding defaultmodelbinder can be used to customize the properties of the model binding.
<summary>///Map a browser request to a data object. </summary> public class Propertymodelbinder:defaultmodelbinder {//<summary>//early Initializes a new instance of the <see cref= "Propertymodelbinder"/> class. </summary> public Propertymodelbinder () {}///<summary>//using the specified controller The following and binding contexts bind the model. </summary>//<param name= "ControllerContext" > Run the controller's context. </param>//<param name= "BindingContext" > the context of the binding model. </param>///<returns> objects that are bound. </returns> public override Object Bindmodel (ControllerContext controllercontext, Modelbindingcontext BINDINGC Ontext) {var model = base. Bindmodel (ControllerContext, BindingContext); if (model is Baseentirymodel) ((Baseentirymodel) model). Bindmodel (ControllerContext, BindingContext); return model; }///<summary>///Use the specified controller context, binding context, property descriptor, and property binder to returnReturns the property value. </summary>//<param name= "ControllerContext" > Run the controller's context. </param>//<param name= "BindingContext" > the context of the binding model. </param>//<param name= "PropertyDescriptor" > Descriptor of the property to be accessed. </param>//<param name= "Propertybinder" > An object that provides a way to bind properties. </param>///<returns> An object that represents the property value. </returns> protected Override Object GetPropertyValue (ControllerContext controllercontext, Modelbindingcontex T BindingContext, System.ComponentModel.PropertyDescriptor PropertyDescriptor, Imodelbinder propertybinder) { var value = base. GetPropertyValue (ControllerContext, BindingContext, PropertyDescriptor, Propertybinder); return value; }///<summary> binds the specified property with the specified controller context, binding context, and specified property descriptor. </summary>//<param name= "ControllerContext" > Run the controller's context. </param>//<param name= "BindingContext" > the context of the binding model. </param>//<param name= "PropertyDescriptor" > describes the properties to bind. </param> protected override void BindProperty (ControllerContext controllercontext, Modelbindingcontext Bindin Gcontext, PropertyDescriptor propertydescriptor) {string fullpropertykey = Createsubpropertyname (Bindin Gcontext.modelname, Propertydescriptor.name); Object propertyvalue = null; if (propertydescriptor.attributes[typeof (propertymodelbinderattribute)]! = null) {var attribute = (Propertymodelbinderattribute) propertydescriptor.attributes[typeof (Propertymodelbinderattribute)]; String propertyname = attribute. PropertyName; var valueresult = BindingContext.ValueProvider.GetValue (PropertyName); if (Valueresult! = null) PropertyValue = Valueresult.attemptedvalue; } else {if (!bindingcontext.valueprovider.containsprefix (Fullpropertykey)) {return; }}//Call to the property ' s model binder Imodelbinder Propertybinder = Binders.getbin Der (Propertydescriptor.propertytype); Object originalpropertyvalue = Propertydescriptor.getvalue (Bindingcontext.model); Modelmetadata propertymetadata = Bindingcontext.propertymetadata[propertydescriptor.name]; Propertymetadata.model = Originalpropertyvalue; Modelbindingcontext innerbindingcontext = new Modelbindingcontext () {modelmetadata = Propertyme Tadata, modelname = fullpropertykey, modelstate = Bindingcontext.modelstate, Valueprovider = Bindingcontext.valueprovider}; Object newpropertyvalue = GetPropertyValue (ControllerContext, Innerbindingcontext, PropertyDescriptor, Propertybinder); if (Newpropertyvalue = = null) {NewpropertYvalue = PropertyValue; } Propertymetadata.model = Newpropertyvalue; Validation modelstate modelstate = Bindingcontext.modelstate[fullpropertykey]; if (modelstate = = NULL | | modelState.Errors.Count = = 0) {if (Onpropertyvalidating (Controllercon Text, BindingContext, PropertyDescriptor, Newpropertyvalue)) {SetProperty (Controllercon Text, BindingContext, PropertyDescriptor, Newpropertyvalue); Onpropertyvalidated (ControllerContext, BindingContext, PropertyDescriptor, Newpropertyvalue); }} else {SetProperty (ControllerContext, BindingContext, Propertydescript Or, Newpropertyvalue); Convert formatexceptions (type conversion failures) into Invalidvalue messages foreach (modelerror error In ModelState.Errors.Where (err = String.IsNullOrEmpty (err. ErrorMessage) &Amp;& Err. Exception! = null). ToList ()) {for (Exception Exception = error. Exception; Exception! = NULL; Exception = exception. innerexception) {//We only consider ' known ' type of exception and do Too aggressive changes here if (Exception are FormatException | | exception is OverflowException) {String displayName = Propertymetadata.getdisplayname (); String errormessagetemplate = Getvalueinvalidresource (ControllerContext); String errormessage = String.Format (CultureInfo.CurrentCulture, Errormessagetemplate, ModelState.Value.AttemptedValue, DisplayName); ModelState.Errors.Remove (Error); MODELSTATE.ERRORS.ADD (errormessage); Break } } } }//base. BindProperty (ControllerContext, BindingContext, PropertyDescriptor); }///<summary>///Use the specified controller context, binding context, and property value to set the specified property. </summary>//<param name= "ControllerContext" > Run the controller's context. </param>//<param name= "BindingContext" > the context of the binding model. </param>//<param name= "PropertyDescriptor" > describes the properties to bind. </param>//<param name= "value" > the value set for the property. </param> protected override void SetProperty (ControllerContext controllercontext, modelbindingcontext binding Context, PropertyDescriptor PropertyDescriptor, object value) {Modelmetadata PropertyMetadata = Binding Context.propertymetadata[propertydescriptor.name]; Propertymetadata.model = value; String modelstatekey = Createsubpropertyname (Bindingcontext.modelname, propertymetadata.propertyname); if (value = = null && BindingContext.ModelState.IsValidField (ModelSTatekey)) {Modelvalidator requiredvalidator = ModelValidatorProviders.Providers.GetValidators (P Ropertymetadata, ControllerContext). Where (v = v.isrequired). FirstOrDefault (); if (requiredvalidator! = null) {foreach (Modelvalidationresult validationresult in requ Iredvalidator.validate (Bindingcontext.model)) {BindingContext.ModelState.AddMod Elerror (Modelstatekey, validationresult.message); }}} bool Isnullvalueonnonnullabletype = value = = NULL &&! Typeallowsnullvalue (Propertydescriptor.propertytype); if (!propertydescriptor.isreadonly &&!isnullvalueonnonnullabletype) {try {var typevalue = Convert.changetype (value, Propertydescriptor.propertytype, Cultureinfo.invariantcul ture); Propertydescriptor.setvalue (Bindingcontext.model, Typevalue); } catch (Exception ex) {if (BindingContext.ModelState.IsValidField (model Statekey)) {bindingContext.ModelState.AddModelError (Modelstatekey, ex); }}} if (Isnullvalueonnonnullabletype && bindingcontext.modelst Ate. Isvalidfield (Modelstatekey)) {BindingContext.ModelState.AddModelError (Modelstatekey, Getvaluere Quiredresource (ControllerContext)); }}///<summary>///Use the specified controller context and binding context to return the properties of the model. </summary>//<param name= "ControllerContext" > Run the controller's context. </param>//<param name= "BindingContext" > the context of the binding model. </param>///<returns> A collection of property descriptors. </returns> protected override PropertyDescriptorCollection getmodelproperties (ControllerContext Controllercon Text, MoDelbindingcontext bindingcontext) {bindingcontext.propertyfilter = new predicate<string> (pred); var values = base. Getmodelproperties (ControllerContext, BindingContext); return values; }///<summary>///Get the decision object for the property filter. </summary>//<param name= The properties of the "target" > property filter. </param>///<returns> a Boolean value. </returns> protected bool Pred (string target) {return true; #region Private ...///<summary>///type allows null values. </summary>//<param name= "type" > Specified type. </param>///<returns> returns True if the type value is NULL, otherwise false is returned. </returns> private static bool Typeallowsnullvalue (type type) {return (!type. Isvaluetype | | Isnullablevaluetype (type)); }///<summary>//is a nullable value type. </summary>//<param name= "type" > Specifyof the type. </param>///<returns> returns True if the type value is NULL, otherwise false is returned. </returns> private static bool Isnullablevaluetype (type type) {return Nullable.getunderlyi Ngtype (type)! = NULL; }///<summary>///For resources with invalid value. </summary>//<param name= "ControllerContext" ></param>//<returns></return s> private static string Getvalueinvalidresource (ControllerContext controllercontext) {return Getuserresourcestring (ControllerContext, "Propertyvalueinvalid")?? "The value ' {0} ' is not valid for {1}."; }///<summary>///Get the resources you need for value. </summary>//<param name= "ControllerContext" ></param>//<returns></return s> private static string Getvaluerequiredresource (ControllerContext controllercontext) {retur N getuserresourcestring (ControllerContext, "PropertyvaluErequired ")?? "A value is required."; } private static string getuserresourcestring (ControllerContext controllercontext, string resourcename) { string result = NULL; if (! String.IsNullOrEmpty (Resourceclasskey) && (controllercontext! = null) && ( Controllercontext.httpcontext = null)) {result = ControllerContext.HttpContext.GetGlobalResour Ceobject (Resourceclasskey, resourcename, cultureinfo.currentuiculture) as String; } return result; } #endregion}
It is important to note that [Modelbinder (typeof (Propertymodelbinder)]) is set on the class of the entity model and is registered in Global.
ModelBinders.Binders.Clear (); ModelBinders.Binders.Add (typeof (Propertysoukemodel), New Propertymodelbinder ());
Custom model bindings for ASP.