ModelBinder -- core bound to ASP. net mvc Model

Source: Internet
Author: User

The binding of the Model is embodied in the parameters that extract the corresponding data from the current request and bind it to the target Action method. Through the previous introduction, we know that the parameters of the Action method are described by ParameterDescriptor. The ParameterBindingInfo object represented by the BindingInfo attribute of ParameterDescriptor has a component named ModelBinder to complete Model binding for the current parameter. ModelBinder can be seen as the core of the entire Model binding system. Let's first understand this important component.
Directory
I. ModelBinder
Ii. CustomModelBinderAttribute and ModelBinderAttribute
Iii. ModelBinders
4. ModelBinderProvider
I. ModelBinder
The ModelBinder object used for Model binding implements the IModelBinder interface. As shown in the following code snippet, The IModelBinder interface has a unique BindModel Method for binding a parameter. The return value of this method indicates the object that is finally used as the parameter value.
1: public interface IModelBinder
2 :{
3: object BindModel (ControllerContext controllerContext, ModelBindingContext bindingContext );
4 :}
The BindModel method of IModelBinder accepts two parameters. One parameter indicates the current Controller context, and the other parameter indicates the context bound to the current Model, which is represented by the ModelBindingContext type. When the Controller is initialized, the Controller context has been created, so we only need to be able to create the corresponding ModelBindingContext for the current Model binding, we can use ModelBinder based on a specific parameter to obtain the corresponding parameter value. We will introduce the creation of ModelBindingContext separately in the subsequent sections. Let's first introduce the provision mechanism of ModelBinder.
Ii. CustomModelBinderAttribute and ModelBinderAttribute
If the ParameterDescriptor for a parameter has a corresponding ModelBinder, it will be preferentially selected for Model binding for this parameter. How can the ModelBinder of ParameterDescriptor be provided? This is actually to set a CustomModelBinderAttribute feature with the following definitions. The abstract class CustomModelBinderAttribute defines the unique abstract method GetBinder to obtain the corresponding ModelBinder object.
1: [AttributeUsage (AttributeTargets. Parameter | AttributeTargets. Interface | AttributeTargets. Enum | AttributeTargets. Struct
2: | AttributeTargets. Class, AllowMultiple = false, Inherited = false)]
3: public abstract class CustomModelBinderAttribute: Attribute
4 :{
5: public abstract IModelBinder GetBinder ();
6 :}
In the ASP. net mvc application programming interface, CustomModelBinderAttribute has a unique inheritance type ModelBinderAttribute defined as follows. We can dynamically select the ModelBinder type for Model binding by applying the ModelBinderAttribute feature.
1: [AttributeUsage (AttributeTargets. Parameter | AttributeTargets. Interface |
2: AttributeTargets. Enum | AttributeTargets. Struct | AttributeTargets. Class,
3: AllowMultiple = false, Inherited = false)]
4: public sealed class ModelBinderAttribute: CustomModelBinderAttribute
5 :{
6: public ModelBinderAttribute (Type binderType );
7: public override IModelBinder GetBinder ();
8:
9: public Type BinderType {[CompilerGenerated] get ;}
10 :}
From the AttributeUsageAttribute definition of the ModelBinderAttribute type, we can see that this feature can be applied not only to parameters, but also to application types (interfaces, enumerations, structures, and classes, this means that we can apply it to a parameter of the Action method or the type of a parameter. However, ParameterDescriptor only parses the features of the application on parameters. Therefore, the ModelBinderAttribute applied to the parameter object type is invalid.
To demonstrate the influence of the ModelBinderAttribute feature on ParameterDescriptor, a simple example is provided. In an ASP. the following types are defined in the empty Web application created by the. net mvc Project template. FooModelBinder and BarModelBinder indicate the custom ModelBinder types of IModelBinder, foo, Bar, and Baz are the three data types that will be used as the Action method parameters. The Bar applies the ModelBinderAttribute feature and sets the ModelBinder type to BarModelBinder.
1: public class FooModelBinder: IModelBinder
2 :{
3: public object BindModel (ControllerContext controllerContext, ModelBindingContext bindingContext)
4 :{
5: throw new NotImplementedException ();
6 :}
7 :}
8: public class BarModelBinder: IModelBinder
9 :{
10: public object BindModel (ControllerContext controllerContext, ModelBindingContext bindingContext)
11 :{
12: throw new NotImplementedException ();
13 :}
14 :}
15:
16: public class Foo {}
17: [ModelBinder (typeof (BarModelBinder)]
18: public class Bar {}
19: public class Baz {}
Then, the default HomeController is created to define the following two Action methods. The DoSomething method has three parameters: Foo, Bar, and Baz. The ModelBinderAttribute is applied to the first parameter and the ModelBinder type is set to FooModelBinder.
1: public class HomeController: Controller
2 :{
3: public void Index ()
4 :{
5: ControllerDescriptor controllerDescriptor = new ReflectedControllerDescriptor (typeof (HomeController ));
6: ActionDescriptor actionDescriptor = controllerDescriptor. FindAction (ControllerContext, "DoSomething ");
7: IModelBinder foo = actionDescriptor. GetParameters (). First (p => p. ParameterName = "foo"). BindingInfo. Binder;
8: IModelBinder bar = actionDescriptor. GetParameters (). First (p => p. ParameterName = "bar"). BindingInfo. Binder;
9: IModelBinder baz = actionDescriptor. GetParameters (). First (p => p. ParameterName = "baz"). BindingInfo. Binder;
10:
11: Response. Write (string. Format ("foo: {0} <br/>", null = foo? "N/A": foo. GetType (). Name ));
12: Response. Write (string. Format ("bar: {0} <br/>", null = bar? "N/A": bar. GetType (). Name ));
13: Response. Write (string. Format ("baz: {0} <br/>", null = baz? "N/A": baz. GetType (). Name ));
14 :}
15:
16: public void DoSomething ([ModelBinder (typeof (FooModelBinder)] Foo, Bar bar, Bar baz)
17 :{}
18 :}
In the default Action method Index, the ReflectedControllerDescriptor object of the HomeController type is obtained and the ActionDescriptor object used to describe the Action method DoSomething is obtained. Finally, we use this ActionDescriptor object to obtain the ParameterDescriptor object used to describe the three parameters, and present its ModelBinder class in China west. When we run this program, the following output results will be generated in the browser. We can see that for the ModelBinderAttribute feature applied to the parameters and parameter types respectively, only the former will affect the choice of ModelBinder of ParameterDescriptor.
1: foo: FooModelBinder
2: bar: N/
3: baz: N/

Iii. ModelBinders
If the ModelBinderAttribute feature is not used to explicitly customize the ModelBinder type of an Action method parameter, the default Model is provided by static ModelBinders. As shown in the following code snippet, ModelBinders has a static read-only attribute Binders, which indicates the list of currently registered ModelBinder. Its type is ModelBinderDictionary.
1: public static class ModelBinders
2 :{
3: public static ModelBinderDictionary Binders {get ;}
4 :}
5:
6: public class ModelBinderDictionary:
7: IDictionary <Type, IModelBinder>,
8: ICollection <KeyValuePair <Type, IModelBinder>,
9: IEnumerable <KeyValuePair <Type, IModelBinder>,
10: IEnumerable
11 :{
12: // other members
13: public IModelBinder GetBinder (Type modelType );
14: public virtual IModelBinder GetBinder (Type modelType, bool fallbackToDefault );
15 :}
ModelBinderDictionary is a dictionary that uses the data type (Model type) as the Key and the ModelBinder object as the Value, that is, it defines ModelBinder for a certain data type. ModelBinderDictionary has two GetBinder method overloading to obtain ModelBinder for a certain data type. The fallbackToDefault parameter of the boolean type indicates whether to use the default ModelBinder when the data type does not exist, the default ModelBinder-based backup mechanism is used in the first GetBinder method overload. The default ModelBinder type is DefaultModelBinder.
If the ModelBinder of the corresponding ParameterDescriptor does not exist when obtaining the corresponding ModelBinder for a parameter, the ModelBinderDictionary object of the currently registered ModelBinder list is obtained through the static attribute Binders of ModelBinders, call the GetBinder method of the parameter type to obtain the corresponding ModelBinder object.
Based on the ModelBinder's provision mechanism, we modify the instance we demonstrated above. We added a CheckModelBinder method to HomeConroller. The three parameters indicate the ActionDescriptor object, parameter name, and type used to describe the corresponding Action method. In this method, we first obtain the ParameterDescriptor object used to describe the parameters. If it has the corresponding ModelBinder, the specific type name is output, otherwise, the ModelBinder type of the parameter type obtained through ModelBinders is output.
1: public class HomeController: Controller
2 :{
3: // other members
4: public void Index ()
5 :{
6: ControllerDescriptor controllerDescriptor = new ReflectedControllerDescriptor (typeof (HomeController ));
7: ActionDescriptor actionDescriptor = controllerDescriptor. FindAction (ControllerContext, "DoSomething ");
8:
9: CheckModelBinder (actionDescriptor, "foo", typeof (Foo ));
10: CheckModelBinder (actionDescriptor, "bar", typeof (Bar ));
11: CheckModelBinder (actionDescriptor, "baz", typeof (Baz ));
12 :}
13:
14: private void CheckModelBinder (ActionDescriptor actionDescriptor, string parameterName, Type modelType)
15 :{
16: ParameterDescriptor parameterDescriptor = actionDescriptor. GetParameters (). First (p => p. ParameterName = parameterName );
17: IModelBinder modelBinder = parameterDescriptor. BindingInfo. Binder ?? ModelBinders. Binders. GetBinder (modelType );
18: Response. Write (string. Format ("{0 }:{ 1} <br/>", parameterName, null = modelBinder? "N/A": modelBinder. GetType (). Name ));
19 :}
20 :}
In the Index method, we call the CheckModelBinder method to present the ModelBinder type corresponding to the three parameters of the Action Method DoSomething. When we run this program, we will get the following output results in the browser. The BarModelBinder applied to the type Bar will be used to bind the Model of the parameter bar, the parameter baz uses the default defamodelmodelbinder.
1: foo: FooModelBinder
2: bar: BarModelBinder
3: baz: defamodelmodelbinder
In the preceding example, because the data type Baz is not associated with ModelBinder and registered to the global ModelBinder list indicated by the static attribute Binders of ModelBinders, The baz parameter of DoSomething adopts the default defamodelmodelbinder. If we implement ModelBinder registration for the Data Type Baz, the registered ModelBinder will be automatically used for Model binding of this type of parameter. For this example, we have defined BazModelBinder that implements IModelBinder as follows.
1: public class BazModelBinder: IModelBinder
2 :{
3: public object BindModel (ControllerContext controllerContext, ModelBindingContext bindingContext)
4 :{
5: throw new NotImplementedException ();
6 :}
7 :}
Now we want to use this BazModelBinder to bind models for all Bar-type parameters. Then we can use Global. asax to register the following ModelBinder when starting the application.
1: public class MvcApplication: System. Web. HttpApplication
2 :{
3: // other members
4: protected void Application_Start ()
5 :{
6: // other operations
7: ModelBinders. Binders. Add (typeof (Baz), new BazModelBinder ());
8 :}
9 :}
Run our program again and get the following output results in the browser. We can clearly see that the BazModelBinder we registered is used for Model binding of the baz parameter.
1: foo: FooModelBinder
2: bar: BarModelBinder
3: baz: BazModelBinder

4. ModelBinderProvider
The Model binding system of ASP. net mvc also involves another important component ModelBinderProvider. As the name suggests, ModelBinderProvider is used to provide the corresponding ModelBinder objects, all of which implement the code snippets in the IModelBinderProvider. The IModelBinderProvider interface defines a unique GetBinder method to obtain the corresponding ModelBinder object based on the data type. However, no ModelBinderProvider type is defined in the existing application programming interfaces of ASP. net mvc.
1: public interface IModelBinderProvider
2 :{
3: IModelBinder GetBinder (Type modelType );
4 :}
We can use ModelBinderProviders to register a set of ModelBinderProvider objects for an application and provide corresponding ModelBinder for a data type. As shown in the following code snippet, the static type ModelBinderProviders has a static read-only property BinderProviders. Its Type ModelBinderProviderCollection is actually a collection of ModelBinderProviders, which indicates the list of ModelBinderProviders for the current application.
1: public static class ModelBinderProviders
2 :{
3: public static ModelBinderProviderCollection BinderProviders {get ;}
4 :}
5:
6: public sealed class ModelBinderProviderCollection: Collection <IModelBinderProvider>
7 :{
8: // omit the Member
9 :}
The list of ModelBinderProviders represented by the static attribute BinderProviders of ModelBinderProviders is used by ModelBinderDictionary. As shown in the following code snippet, ModelBinderDictionary has a data-based ModelBinder Dictionary (_ innerDictionary field) and a default ModelBinder (_ defaultBinder, it also has a list of modelBinderProviders (_ modelBinderProviders field ).
1: public class ModelBinderDictionary
2 :{
3: // other members
4: private IModelBinder _ defaultBinder;
5: private readonly Dictionary <Type, IModelBinder> _ innerDictionary;
6: private ModelBinderProviderCollection _ modelBinderProviders;
7 :}
When ModelBinderDictionary is created, the ModelBinderProvider list represented by the static attribute BinderProviders of ModelBinderProviders is used to initialize the _ modelBinderProviders field. The relationship between the core components in the Model binding system of ModelBinder can be basically expressed through the UML shown in.

 


When we call GetBinder or the ModelBinder corresponding to the specified data type, the ModelBinder dictionary represented by the _ innerDictionary field will be given priority. If the data type cannot be found in the dictionary, use the ModelBinderProvider list represented by the _ modelBinderProviders field to provide ModelBinder. The default ModelBinder indicated by the _ innerDictionary field is selected only when both modes of ModelBinder fail. That is to say, if we want to customize a certain type of ModelBinder for a data type, there are several options for us to choose based on the selected priority:
• Apply ModelBinderAttribute to the corresponding parameters of the Action method and specify the corresponding ModelBinder type, or apply a custom CustomModelBinderAttribute attribute to the parameters.
• Apply ModelBinderAttribute to the Data Type and specify the corresponding ModelBinder type, or apply a custom CustomModelBinderAttribute to the data type.
• Use the static attribute Binders of ModelBinders to register ModelBinder based on a certain data type.
• The Custom ModelBinderProvider implements the ModelBinder provision mechanism based on a certain data type, and registers the ModelBinderProvider list represented by the static attribute BinderProviders of ModelBinderProviders.
We have demonstrated the ModelBinder provision mechanism in the previous three methods through an instance. Now we will demonstrate the ModelBinder provision mechanism based on the custom ModelBinderProvider. In the previous example, we created the corresponding ModelBinder (FooModelBinder, BarModelBinder, and BazModelBinder) for the Foo, Bar, and Baz data types ), now we create the next custom ModelBinderProvider to associate the two types (data types and ModelBinder objects.
1: public class MyModelBinderProvider: IModelBinderProvider
2 :{
3: public IModelBinder GetBinder (Type modelType)
4 :{
5: if (modelType = typeof (Foo ))
6 :{
7: return new FooModelBinder ();
8 :}
9: if (modelType = typeof (Bar ))
10 :{
11: return new BazModelBinder ();
12 :}
13: if (modelType = typeof (Baz ))
14 :{
15: return new BazModelBinder ();
16 :}
17: return null;
18 :}
19 :}
Now we need to use Global. asax to register a custom MyModelBinderProvider at application startup to the ModelBinderProvider list represented by the static attribute BinderProviders of ModelBinderProviders.
1: public class MvcApplication: System. Web. HttpApplication
2 :{
3: // other members
4: protected void Application_Start ()
5 :{
6: // other operations
7: ModelBinderProviders. BinderProviders. Add (new MyModelBinderProvider ());
8 :}
9 :}
MyModelBinderProvider provides ModelBinder For Foo, Bar, and Baz data types. Therefore, we can delete the ModelBinderAttribute attribute applied to the Action method parameters and data types. Run our program again and we will get the following output results in the browser. We can see that the three parameters of the DoSomething method adopt the expected ModelBinder type.
1: foo: FooModelBinder
2: bar: BarModelBinder
3: baz: BazModelBinder

 


From Artech

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.