Let's start by looking at the binder properties of Reflectedparameterbindinginfo:
public override Imodelbinder Binder {
get {
Imodelbinder Binder = Modelbinders.getbinderfromattributes (_parameterinfo,
() = String.Format (CultureInfo.CurrentCulture, Mvcresources.reflectedparameterbindinginfo_ Multipleconverterattributes,
_parameterinfo.name, _parameterinfo.member));
return binder;
}
}
In Modelbinders there is a property public static modelbinderdictionary binders, this binders content is as follows
Modelbinderdictionary binders =new modelbinderdictionary () {
{typeof (HttpPostedFileBase), New Httppostedfilebasemodelbinder ()},
{typeof (byte[]), New Bytearraymodelbinder ()},
{typeof (Binary), New Linqbinarymodelbinder ()}
};
The description defaults to the provider 3 binders, but this property is common static, so we can add our own binder class, and the previous article on the Filiter and the following to talk about the Valueprovider,
As in the Application_Start () method ModelBinders.Binders.Add (xxx,xxxx) is not very convenient to expand.
Modelbinders's getbinderfromattributes this way we can guess the logic of it,
Custommodelbinderattribute[] Attrs = (custommodelbinderattribute[]) element. GetCustomAttributes (typeof (Custommodelbinderattribute), True/* inherit */);
Gets the Custommodelbinderattribute attribute of the current parameter, if there is an attribute that invokes the Getbinder () method of the first attribute and returns its value, no attribute returns NULL, and if more than one attribute throws an exception, Note that a parameter is not allowed to have more than one Custommodelbinderattribute attribute, and the binder property of the Reflectedparameterbindinginfo is set.
The following is the turn of the Controlleractioninvoker binders property,
protected Internal modelbinderdictionary binders {
get {
if (_binders = = null) {
_binders = modelbinders.binders;
}
return _binders;
}
set {
_binders = value;
}
}
You can see by default that he is returning modelbinders.binders.
Next look at Imodelbinder binder = Getmodelbinder (parameterdescriptor) How exactly does this sentence return to the binder,
Return ParameterDescriptor.BindingInfo.Binder?? Binders.getbinder (Parameterdescriptor.parametertype);
It's too easy, first of all to see if the parameter has a binder property, and if it returns the binder, the binder is obtained based on the parameter type.
The method is as follows:
[CSharp]
Public Imodelbinder Getbinder (Type modeltype) {
Return Getbinder (Modeltype, True/* fallbacktodefault */);
}
Public virtual Imodelbinder Getbinder (Type modeltype, bool Fallbacktodefault) {
if (Modeltype = = null) {
throw new ArgumentNullException ("Modeltype");
}
Return Getbinder (Modeltype, (Fallbacktodefault)? Defaultbinder:null);
}
Private Imodelbinder Getbinder (Type modeltype, Imodelbinder fallbackbinder) {
Try to look up a binder for this type. We Use this order of precedence:
1. Binder returned from provider
2. Binder registered in the global table
3. Binder attribute defined on the type
4. Supplied Fallback binder
Imodelbinder Binder = _modelbinderproviders.getbinder (Modeltype);
if (binder! = null) {
return binder;
}
if (_innerdictionary.trygetvalue (Modeltype, out binder)) {
return binder;
}
Binder = Modelbinders.getbinderfromattributes (Modeltype,
() = String.Format (CultureInfo.CurrentCulture, Mvcresources.modelbinderdictionary_multipleattributes, Modeltype.fullname));
Return binder?? Fallbackbinder;
}
Public Imodelbinder Getbinder (Type modeltype) {
Return Getbinder (Modeltype, True/* fallbacktodefault */);
}
Public virtual Imodelbinder Getbinder (Type modeltype, bool Fallbacktodefault) {
if (Modeltype = = null) {
throw new ArgumentNullException ("Modeltype");
}
Return Getbinder (Modeltype, (Fallbacktodefault)? Defaultbinder:null);
}
Private Imodelbinder Getbinder (Type modeltype, Imodelbinder fallbackbinder) {
//Try to look up a binder for this type. We Use this order of precedence:
//1. Binder returned from provider
//2. Binder registered in the global table
//3. Binder attribute defined on the type
//4. Supplied Fallback binder
Imodelbinder Binder = _modelbinderproviders.getbinder (Modeltype);
if (binder! = null) {
return binder;
}
if (_innerdictionary.trygetvalue (Modeltype, out binder)) {
return binder;
}
Binder = Modelbinders.getbinderfromattributes (Modeltype,
() = String.Format (CultureInfo.CurrentCulture, Mvcresources.modelbinderdictionary_multipleattributes, Modeltype.fullname));
Return binder?? Fallbackbinder;
}
It is important to note that the binder is selected in order of precedence, (1) to find the appropriate binder from the _modelbinderproviders
private modelbinderprovidercollection _modelbinderproviders;
Public modelbinderdictionary ()
: This (modelbinderproviders.binderproviders) {
}
Internal modelbinderdictionary ( Modelbinderprovidercollection modelbinderproviders) {
_modelbinderproviders = modelbinderproviders;
}
public static class Modelbinderproviders {
Private readonly static Modelbinderprovidercollection _binderproviders = new Modelbinderprovidercollection {
};
public static modelbinderprovidercollection Binderproviders {
get {
return _binderproviders;
}
}
}
From this code we can learn that by default _modelbinderproviders there is no data, then when this set has data, when we are in Application_Start () Call MODELBINDERPROVIDERS.BINDERPROVIDERS.ADD (XXX) in the data,
(2) Take data from _innerdictionary, when this data is added up, see the modelbinderdictionary add put it to understand
public void Add (Type key, Imodelbinder value) {
_innerdictionary.add (key, value);
}
In fact, modelbinderdictionary internal many methods are around the _innerdictionary collection operation.
(3) Obtaining binder from the parameter data type
(4) Return default DefaultBinder, this property default = new Defaultmodelbinder ()
Now we can summarize the binder precedence (1) Custommodelbinderattribute characteristics on the parameter, (2) ModelBinderProviders.BinderProviders.Add (XXX) Registered Imodelbinderprovider; (3) Modelbinders of binders; (4) Custommodelbinderattribute characteristics on parameter types ; (5) returns the default Defaultmodelbinder
Ivalueprovider valueprovider = ControllerContext.Controller.ValueProvider; Let's put it in the back of the article,
String parametername = ParameterDescriptor.BindingInfo.Prefix?? Parameterdescriptor.parametername This sentence gets the parameter name,
Predicate<string> propertyfilter = Getpropertyfilter (parameterdescriptor); This will only control the parameter when the corresponding value needs to be bound.
private static predicate<string> Getpropertyfilter (Parameterdescriptor parameterdescriptor) {
Parameterbindinginfo bindinginfo = Parameterdescriptor.bindinginfo;
Return propertyname = bindattribute.ispropertyallowed (PropertyName, BindingInfo.Include.ToArray (), BindingInfo.Exclude.ToArray ());
}
Bindattribute.ispropertyallowed as follows:
Internal static bool Ispropertyallowed (String propertyname, string[] includeproperties, string[] excludeproperties) {
We allow a property to being bound if its both in the include list and not in the exclude list.
An empty include list implies all properties is allowed.
An empty exclude list implies no properties is disallowed.
BOOL Includeproperty = (Includeproperties = = null) | | (Includeproperties.length = = 0) | | Includeproperties.contains (PropertyName, Stringcomparer.ordinalignorecase);
BOOL Excludeproperty = (excludeproperties! = null) && excludeproperties.contains (PropertyName, Stringcomparer.ordinalignorecase);
return Includeproperty &&!excludeproperty;
}
Now finally saw the bindattribute in the declaration of the use of the place.
Now let's do a custom Modelbinder class.
[CSharp]
public class UserInfo
{
public string Name {set; get;}
public string Age {set; get;}
}
public class Userinfomodelbinder:imodelbinder
{
public Object Bindmodel (ControllerContext controllercontext, Modelbindingcontext BindingContext)
{
Object obj = Activator.CreateInstance (bindingcontext.modeltype);
foreach (PropertyInfo p in bindingContext.ModelType.GetProperties ())
{
Valueproviderresult vpresult= BindingContext.ValueProvider.GetValue (p.name);
if (Vpresult! = null)
{
Object value = Vpresult.convertto (P.propertytype);
P.setvalue (obj, value, null);
}
}
return obj;
}
}
public class Homecontroller:controller
{
Public ActionResult Index ([Modelbinder (typeof (Userinfomodelbinder))]userinfo UserInfo)
{
Return Content ("Name:" + Userinfo.name + "Age:" + userinfo.age);
return View ();
}
}
public class UserInfo
{
public string Name {set; get;}
public string Age {set; get;}
}
public class Userinfomodelbinder:imodelbinder
{
public Object Bindmodel (ControllerContext controllercontext, Modelbindingcontext BindingContext)
{
Object obj = Activator.CreateInstance (bindingcontext.modeltype);
foreach (PropertyInfo p in bindingContext.ModelType.GetProperties ())
{
Valueproviderresult vpresult= BindingContext.ValueProvider.GetValue (p.name);
if (Vpresult! = null)
{
Object value = Vpresult.convertto (P.propertytype);
P.setvalue (obj, value, null);
}
}
return obj;
}
}
public class Homecontroller:controller
{
Public ActionResult Index ([Modelbinder (typeof (Userinfomodelbinder))]userinfo UserInfo)
{
Return Content ("Name:" + Userinfo.name + "Age:" + userinfo.age);
return View ();
}
Run results