通过实例模拟ASP.NET MVC的Model绑定的机制:集合+字典

在本系列的前面两篇文章(《简单类型+复杂类型》、《数组》)我们通过创建的实例程序模拟了ASP.NET MVC默认使用的DefaultModelBinder对简单类型、复杂类型以及数组对象的Model绑定。现在我们按照相同的方式来分析基于集合和字典类型的Model绑定是如何实现的。[源代码从这里下载]

一、集合

这里的集合指的是除数组和字典之外的所有实现IEnumerable<T>接口的类型。和基于数组的Model绑定类似,ValueProvider可以将多个同名的数据项作为集合的元素,基于索引(基零整数和字符串)的数据项命名方式同样适用。我们对自定义的DefaultModelBinder作了如下的完善使之支持集合类型的Model绑定。

   1: public class DefaultModelBinder   2: {   3:     //其他成员   4:     public object BindModel(Type parameterType, string prefix)   5:     {   6:         if (!this.ValueProvider.ContainsPrefix(prefix))   7:         {   8:             return null;   9:         }  10:         ModelMetadata modelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => null, parameterType);  11:         if (!modelMetadata.IsComplexType)  12:         {  13:             return this.ValueProvider.GetValue(prefix).ConvertTo(parameterType);  14:         }  15:         if (parameterType.IsArray)  16:         {  17:             return BindArrayModel(parameterType, prefix);  18:         }  19:         object model = CreateModel(parameterType);  20:         Type enumerableType = ExtractGenericInterface(parameterType, typeof(IEnumerable<>));  21:         if (null != enumerableType)  22:         {  23:             return BindCollectionModel(prefix, model, enumerableType);  24:         }  25:         foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(parameterType))  26:         {  27:             string key = prefix == "" ? property.Name : prefix + "." + property.Name;  28:             property.SetValue(model, BindModel(property.PropertyType, key));  29:         }  30:         return model;  31:     }  32:  33:     private object BindCollectionModel(string prefix, object model, Type enumerableType)  34:     {  35:         List<object> list = new List<object>();  36:         bool numericIndex;  37:         IEnumerable<string> indexes = GetIndexes(prefix, out numericIndex);  38:         Type elementType = enumerableType.GetGenericArguments()[0];  39:  40:         if (!string.IsNullOrEmpty(prefix) && this.ValueProvider.ContainsPrefix(prefix))  41:         {  42:             IEnumerable enumerable = this.ValueProvider.GetValue(prefix).ConvertTo(enumerableType) as IEnumerable;  43:             if (null != enumerable)  44:             {  45:                 foreach (var value in enumerable)  46:                 {  47:                     list.Add(value);  48:                 }  49:             }  50:         }  51:         foreach (var index in indexes)  52:         {  53:             string indexPrefix = prefix + "[" + index + "]";  54:             if (!this.ValueProvider.ContainsPrefix(indexPrefix) && numericIndex)  55:             {  56:                 break;  57:             }  58:             list.Add(BindModel(elementType, indexPrefix));  59:         }  60:         if (list.Count == 0)  61:         {  62:             return null;  63:         }  64:         ReplaceHelper.ReplaceCollection(elementType, model, list);  65:         return model;  66:     }  67:  68:     private Type ExtractGenericInterface(Type queryType, Type interfaceType)  69:     {  70:         Func<Type, bool> predicate = t => t.IsGenericType && (t.GetGenericTypeDefinition() == interfaceType);  71:         if (!predicate(queryType))  72:         {  73:             return queryType.GetInterfaces().FirstOrDefault<Type>(predicate);  74:         }  75:         return queryType;  76:     }  77: }

如上面的代码片断所示,在BindModel方法中我们通过调用ExtractGenericInterface判断目标类型是否实现了IEnumerable<T>接口,如果实现了该接口则提取泛型元素类型。针对集合的Model绑定实现在方法BindCollectionModel中,我们按照数组绑定的方式得的针对目标集合对象的所有元素对象,并将其添加到一个List<object>对象中,然后调用ReplaceHelper 的静态方法ReplaceCollection将该列表中的元素拷贝到预先创建的Model对象中。定义在ReplaceHelper的静态方法ReplaceCollection定义如下:

   1: internal static class ReplaceHelper   2: {   3:     private static MethodInfo replaceCollectionMethod = typeof(ReplaceHelper).GetMethod("ReplaceCollectionImpl", BindingFlags.Static |BindingFlags.NonPublic);   4:   5:      public static void ReplaceCollection(Type collectionType, object collection, object newContents)   6:     {   7:         replaceCollectionMethod.MakeGenericMethod(new Type[] { collectionType }).Invoke(null, new object[] { collection, newContents });   8:     }   9:     private static void ReplaceCollectionImpl<T>(ICollection<T> collection, IEnumerable newContents)  10:     {  11:         collection.Clear();  12:         if (newContents != null)  13:         {  14:             foreach (object obj2 in newContents)  15:             {  16:                 T item = (obj2 is T) ? ((T)obj2) : default(T);  17:                 collection.Add(item);  18:             }  19:         }  20:     }  21: }

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索数组
, object
, return
, 字典数组
, 类型
, ienumerable
, 模拟类机制
asp数据字典
,以便于您获取更多的相关知识。

时间: 2025-01-01 13:48:34

通过实例模拟ASP.NET MVC的Model绑定的机制:集合+字典的相关文章

通过实例模拟ASP.NET MVC的Model绑定机制:数组

[续<通过实例模拟ASP.NET MVC的Model绑定机制:简单类型+复杂类型]>]基于数组和集合类型的Model绑定机制比较类似,对于绑定参数类型或者参数类型的某个属性为数组或者集合,如果ValueProvider根据对应的Key能够匹配多条数据,那么这些数据最终将会转换为绑定的数组/集合的元素.此外,针对数组/集合的Model绑定还支持基于索引的方式.[源代码从这里下载] 一.基于名称的数组绑定 对于针对NameValueConllectionProvider来说,通过GetValue方

通过实例模拟ASP.NET MVC的Model绑定机制:简单类型+复杂类型

总的来说,针对目标Action方法参数的Model绑定完全由组件ModelBinder来实现,在默认情况下使用的ModelBinder类型为DefaultModelBinder,接下来我们将按照逐层深入的方式介绍实现在DefaultModelBinder的默认Model绑定机制.[源代码从这里下载] 一.简单类型 对于旨在绑定目标Action方法参数值的Model来说,最简单的莫过于简单参数类型的情况.通过<初识Model元数据>的介绍我们知道,复杂类型和简单类型之间的区别仅仅在于是否支持针对

ASP.NET MVC的Model元数据提供机制的实现

在前面的介绍中我们已经提到过表示Model元数据的ModelMetadata对象最终是通过一个名为ModelMetadataProvider的组件提供的,接下来我们着重讨论基于ModelMetadataProvider的Model元数据提供机制及其扩展. 一. ModelMetadataProvider 在ASP.NET MVC的Model元数据相关的应用编程接口中,用于创建Model元数据的ModelMetadataProvider接继承自抽象类ModelMetadataProvider.如下

ASP.NET MVC的Model元数据与Model模板:将”ListControl”引入ASP.NET MVC

我们不仅可以创建相应的模板来根据Model元数据控制种类型的数据在UI界面上的呈现方法,还可以通过一些扩展来控制Model元数据本身.在某些情况下通过这两者的结合往往可以解决很多特殊数据的呈现问题,我们接下来演示的实例就是典型的例子.[本文已经同步到<How ASP.NET MVC Works?>中] 传统的ASP.NET具有一组重要的控件类型叫做列表控件(ListControl),它的子类包括DropDownList.ListBox.RadioButtonList和CheckBoxList等

ASP.NET MVC的Model、DTO、Command的区别

最近在用CQRS架构模式做项目,有些感悟,记录下来. 问题的描述(大家是否也存在过类似的情况呢?): 从刚开始时项目中没有区分这3种对象,所以导致了很多职责公用,然后就乱了,比如Command一部分职责 需要用到ASP.NET MVC中,所以定义在了底层dll中,并且贴了一堆一堆的DataAnnotation的tag到属性上,其 中包括了很多remote验证.前端js validation组件的验证tag,很宏伟.后端CommandHandler那边传入 DomainService的dll中,由

ASP.NET MVC 3 Model的使用?

昨天博客发了新文章,讲一下我对如何使用MVC中的Model的看法,不是什么大技术,当是一个技术讨论^^ 原文地址:http://www.youguanbumen.net/Article.aspx?id=79 原文: 前两天写了个文章ASP.NET MVC 3 -- Model远程验证,主要记录了一下ASP.NET MVC 3中新增的RemoteAttribute类的使用,得益于这个类,我们可以在模型中为属性配置客户端远程校验的业务,文章中给了出一个简单的实体类MyUser_Add,举了一个最常见

ASP.NET MVC数组模型绑定详解_实用技巧

在ASP.NET MVC中使用Razor语法可以在视图中方便地展示数组,如果要进行数组模型绑定,会遇到索引断裂问题,如下示例: <input type="text" name="[0].Name" /> <input type="text" name="[1].Name" /> <input type="text" name="[2].Name" />

ASP.NET MVC的Model元数据与Model模板:将”ListControl”引入ASP.NET MVC

我们不仅可以创建相应的模板来根据Model元数据控制种类型的数据在UI界面上的呈现方法,还可以通过一些扩展来控制Model元数据本身.在某些情况下通过这两者的结合往往可以解决很多特殊数据的呈现问题,我们接下来演示的实例就是典型的例子. 传统的ASP.NET具有一组重要的控件类型叫做列表控件(ListControl),它的子类包括DropDownList.ListBox.RadioButtonList和CheckBoxList等.对于ASP.NET MVC来说,我们可以通过HtmlHelper/H

ASP.NET MVC的Model元数据与Model模板:预定义模板

通过ModelMetadata表示的Model元数据的一个主要的作用在于为定义在HtmlHelper和HtmlHelper<TModel>中的模板方法(这些模板方法包括Display/DisplayFor.Editor/EditorFor.DisplayForModel/EditForModel.Lable/LabelFor和DisplayText/DisplayTextFor等)提供用于最终生成HTML的元数据信息.在调用这些方法的时候,如果我们指定了一个具体的通过分部View定义的模板,或