日期:2014-05-17  浏览次数:21097 次

asp.net mvc源码分析-DefaultModelBinder 集合绑定

接着上篇关于数据绑定的asp.net mvc源码分析-DefaultModelBinder 自定义的普通数据类型的绑定和验证里面只讲了复杂数据类型的绑定,还有上面集合、字典等这些数据这么绑定的了。说到集合绑定其实网上已经有很多关于它的介绍通过实例模拟ASP.NET MVC的Model绑定机制:数组。这个我先举一个使用例子吧:

后端代码:


前端代码:

运行结果:


好,现在让我们来看看集合的数据究竟是怎么绑定的吧:

在BindComplexModel方法中有这么一段:

  Type enumerableType = TypeHelpers.ExtractGenericInterface(modelType, typeof(IEnumerable<>));
            if (enumerableType != null) {
                Type elementType = enumerableType.GetGenericArguments()[0];

                Type collectionType = typeof(ICollection<>).MakeGenericType(elementType);
                if (collectionType.IsInstanceOfType(model)) {
                    ModelBindingContext collectionBindingContext = new ModelBindingContext() {
                        ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, modelType),
                        ModelName = bindingContext.ModelName,
                        ModelState = bindingContext.ModelState,
                        PropertyFilter = bindingContext.PropertyFilter,
                        ValueProvider = bindingContext.ValueProvider
                    };
                    object collection = UpdateCollection(controllerContext, collectionBindingContext, elementType);
                    return collection;
                }
            }

在这里TypeHelpers.ExtractGenericInterface方法主要是用来检查modelType是否是一个集合类型,Type elementType = enumerableType.GetGenericArguments()[0];这句就是获取集合元素类型,在这个例子中它是UserInfo的类型。  Type collectionType = typeof(ICollection<>).MakeGenericType(elementType);这句也很好理解,就是创建一个elementType的集合类型,后面再看看当前的model是否是这个集合类型的实例,要注意一下默认这里的model是没有什么实际内容的,但是它也不为null,后面紧接着创建新的ModelBindingContext,最后调用UpdateCollection方法,看来绑定的关键还是在UpdateCollection方法里面:

internal object UpdateCollection(ControllerContext controllerContext, ModelBindingContext bindingContext, Type elementType) {
            bool stopOnIndexNotFound;
            IEnumerable<string> indexes;
            GetIndexes(bindingContext, out stopOnIndexNotFound, out indexes);
            IModelBinder elementBinder = Binders.GetBinder(elementType);

            // build up a list of items from the request
            List<ob