asp.net MVC 4.0 Controller回顾——ModelBinding过程

以DefaultModelBinder为例

为简单模型绑定(BindSimpleModel)和复杂模型绑定(BindSimpleModel)

 1 public virtual object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
 2         {
 3             if (bindingContext == null)
 4             {
 5                 throw new ArgumentNullException("bindingContext");
 6             }
 7             bool flag = false;
 8             if (!string.IsNullOrEmpty(bindingContext.ModelName) && !bindingContext.ValueProvider.ContainsPrefix(bindingContext.ModelName))
 9             {
10                 .......
11             }
12             if (!flag)
13             {
14                 .......
15                 if (valueProviderResult != null)
16                 {
17                     return this.BindSimpleModel(controllerContext, bindingContext, valueProviderResult);
18                 }
19             }
20             if (!bindingContext.ModelMetadata.IsComplexType)
21             {
22                 return null;
23             }
24             return this.BindComplexModel(controllerContext, bindingContext);
25         }

 

 

复杂类型

 绑定类型为复杂类型是绑定属性

internal void BindComplexElementalModel(ControllerContext controllerContext, ModelBindingContext bindingContext, object model)
        {
            ModelBindingContext context = this.CreateComplexElementalModelBindingContext(controllerContext, bindingContext, model);
            if (this.OnModelUpdating(controllerContext, context))
            {
                this.BindProperties(controllerContext, context);
                this.OnModelUpdated(controllerContext, context);
            }
        }

遍历属性描述进行绑定

1 private void BindProperties(ControllerContext controllerContext, ModelBindingContext bindingContext)
2         {
3             foreach (PropertyDescriptor descriptor in this.GetFilteredModelProperties(controllerContext, bindingContext))
4             {
5                 this.BindProperty(controllerContext, bindingContext, descriptor);
6             }
7         }

这时又会把bindingContext.ModelName和propertyDescriptor.Name进行组合成为新的前缀进行值得获取,并且获取新的ModelBindingContext进行绑定

 1 protected virtual void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor)
 2  {
 3             string prefix = CreateSubPropertyName(bindingContext.ModelName, propertyDescriptor.Name);
 4             if (bindingContext.ValueProvider.ContainsPrefix(prefix))
 5             {
 6                 IModelBinder propertyBinder = this.Binders.GetBinder(propertyDescriptor.PropertyType);
 7                 object obj2 = propertyDescriptor.GetValue(bindingContext.Model);
 8                 ModelMetadata metadata = bindingContext.PropertyMetadata[propertyDescriptor.Name];
 9                 metadata.Model = obj2;
10                 ModelBindingContext context = new ModelBindingContext {
11                     ModelMetadata = metadata,
12                     ModelName = prefix,
13                     ModelState = bindingContext.ModelState,
14                     ValueProvider = bindingContext.ValueProvider
15                 };
16                 object obj3 = this.GetPropertyValue(controllerContext, context, propertyDescriptor, propertyBinder);
17   ......
18 }

 

 

集合类型、数组类型

 

 1 internal object BindComplexModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
 2 {
 3    ......
 4    Type type7 = TypeHelpers.ExtractGenericInterface(modelType, typeof(IEnumerable<>));
 5             if (type7 != null)
 6             {
 7                 Type type8 = type7.GetGenericArguments()[0];
 8                 if (typeof(ICollection<>).MakeGenericType(new Type[] { type8 }).IsInstanceOfType(model))
 9                 {
10                     ModelBindingContext context6 = new ModelBindingContext();
11                     if (func2 == null)
12                     {
13                         func2 = () => model;
14                     }
15                     context6.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(func2, modelType);
16                     context6.ModelName = bindingContext.ModelName;
17                     context6.ModelState = bindingContext.ModelState;
18                     context6.PropertyFilter = bindingContext.PropertyFilter;
19                     context6.ValueProvider = bindingContext.ValueProvider;
20                     ModelBindingContext context5 = context6;
21                     return this.UpdateCollection(controllerContext, context5, type8);
22                 }
23             }
24    ......
25 }

GetIndexes()获取Name=Index的IEnumerable<string>集合(字符串索引集合),再根据ModelName+[当前索引前缀],进行模型绑定,通过ValueProvider.ContainsPrefix(prefix)判断是否包含当前前缀的,重新获取elementType的ModelBindingContext进行模型绑定(elementType为集合类型,通过 type7.GetGenericArguments()[0]获取到

internal object UpdateCollection(ControllerContext controllerContext, ModelBindingContext bindingContext, Type elementType)
        {
            bool flag;
            IEnumerable<string> enumerable;
            GetIndexes(bindingContext, out flag, out enumerable);
            IModelBinder binder = this.Binders.GetBinder(elementType);
            List<object> newContents = new List<object>();
            foreach (string str in enumerable)
            {
                string prefix = CreateSubIndexName(bindingContext.ModelName, str);
                if (!bindingContext.ValueProvider.ContainsPrefix(prefix))
                {
                    if (!flag)
                    {
                        continue;
                    }
                    break;
                }
                ModelBindingContext context = new ModelBindingContext {
                    ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, elementType),
                    ModelName = prefix,
                    ModelState = bindingContext.ModelState,
                    PropertyFilter = bindingContext.PropertyFilter,
                    ValueProvider = bindingContext.ValueProvider
                };
                object obj2 = binder.BindModel(controllerContext, context);
                AddValueRequiredMessageToModelState(controllerContext, bindingContext.ModelState, prefix, elementType, obj2);
                newContents.Add(obj2);
            }
            if (newContents.Count == 0)
            {
                return null;
            }
            object model = bindingContext.Model;
            CollectionHelpers.ReplaceCollection(elementType, model, newContents);
            return model;
        }

 View代码

 1 @using System.Collections.ObjectModel
 2 @model ObservableCollection<MvcSource.Models.LogOnModel>
 3 
 4 @Html.LabelFor(m => m[0].UserName)
 5 @Html.LabelFor(m => m[0].Password)
 6 @Html.CheckBoxFor(m => m[0].RememberMe)
 7 
 8 @Html.LabelFor(m => m[1].UserName)
 9 @Html.LabelFor(m => m[1].Password)
10 @Html.CheckBoxFor(m => m[1].RememberMe)

生成出来的HTML源码

1 <input name="[0].UserName" type="text" value="" />
2 <input name="[0].Password" type="password" />
3 <input name="[0].RememberMe" type="checkbox" value="true" />
4 
5 <input name="[1].UserName" type="text" value="" />
6 <input name="[1].Password" type="password" />
7 <input name="[1].RememberMe" type="checkbox" value="true" />

Controller调用方法参数为List<T>

1 [HttpPost]
2 public ActionResult LogOn(List<LogOnModel> UserName)
3 {
4     return View();
5 }

上面分析UpdateCollection 时这时候模型绑定的前缀为 [0].UserName

NameValueCollectionValueProvider类获取key值

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。