<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      通過實例模擬ASP.NET MVC的Model綁定的機制:集合+字典

      在本系列的前面兩篇文章(《簡單類型+復雜類型》、《數組》)我們通過創建的實例程序模擬了ASP.NET MVC默認使用的DefaultModelBinder對簡單類型、復雜類型以及數組對象的Model綁定。現在我們按照相同的方式來分析基于集合和字典類型的Model綁定是如何實現的。[源代碼從這里下載][本文已經同步到《How ASP.NET MVC Works?》中]

      一、集合

      這里的集合指的是除數組和字典之外的所有實現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: }

      為了讓演示針對集合類型的Model綁定,我們對實例中的HomeController作了如下的修改。Action方法的參數類型替換成IEnumerable<Contact>,該集合中的每個Contact的信息在該方法中被呈現出來。通過GetValueProvider提供的NameValueCollectionValueProvider采用基零整數索引的方式定義數據項。

         1: public class HomeController : Controller
         2: {
         3:     private IValueProvider GetValueProvider()
         4:     {
         5:         NameValueCollection requestData = new NameValueCollection();
         6:         requestData.Add("[0].Name", "Foo");
         7:         requestData.Add("[0].PhoneNo", "123456789");
         8:         requestData.Add("[0].EmailAddress", "Foo@gmail.com");
         9:  
        10:         requestData.Add("[1].Name", "Bar");
        11:         requestData.Add("[1].PhoneNo", "987654321");
        12:         requestData.Add("[1].EmailAddress", "Bar@gmail.com");
        13:  
        14:         return new NameValueCollectionValueProvider(requestData, CultureInfo.InvariantCulture);
        15:     }
        16:          
        17:     public void Action(IEnumerable<Contact> contacts)
        18:     {
        19:         foreach (Contact contact in contacts)
        20:         {
        21:             Response.Write(string.Format("{0}: {1}<br/>", "Name", contact.Name));
        22:             Response.Write(string.Format("{0}: {1}<br/>", "Phone No.", contact.PhoneNo));
        23:             Response.Write(string.Format("{0}: {1}<br/><br/>", "Email Address",contact.EmailAddress));
        24:         }
        25:     }
        26: }

      該程序被執行之后,在瀏覽器上依然會呈現出如下所示的我們希望的數據,這充分證明了我們自定義的DefaultModelBinder具有針對集合的綁定能力。

         1: Name: Foo
         2: PhoneNo: 123456789
         3: EmailAddress: Foo@gmail.com
         4:  
         5: Name: Bar
         6: PhoneNo: 987654321
         7: EmailAddress: Bar@gmail.com

      二、 字典

      這里的字典指的是實現了接口IDictionary<TKey,TValue>的類型。在Model綁定過程中基于字典類型的數據映射很好理解,首先,字典是一個KeyValuePair<TKey,TValue>對象的集合,所以在字典元素這一級可以采用基于索引的匹配機制;其次,KeyValuePair<TKey,TValue>是一個復雜類型,可以按照屬性名稱(Key和Value)進行匹配。比如說作為某個ValueProvider數據源的NameValueCollection具有如下的結構,它可以映射為一個IDictionary<string, Contact>對象(Contact對象作為Value,其Name屬性作為Key)。

         1: [0].Key               : Foo
         2: [0].Value.Name        : Foo
         3: [0].Value.EmailAddress: Foo@gmail.com
         4: [0].Value.PhoneNo     : 123456789
         5:  
         6: [1].Key               : Bar
         7: [1].Value.Name        : Bar
         8: [1].Value.EmailAddress: Bar@gmail.com
         9: [1].Value.PhoneNo     : 987654321

      現在我們對用于模擬默認Model綁定的自定義DefaultModelBinder作最后的完善,使之支持針對字典類型的Model綁定。如下面的代碼片斷所示,在通過調用CreateModel創建Model對象之后,我們調用ExtractGenericInterface方法判斷目標類型是否是一個字典,如果是則返回具體的字典類型,然后調用BindDictionaryModel方法實施針對字典類型的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:  
        11:         ModelMetadata modelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => null, parameterType);
        12:         if (!modelMetadata.IsComplexType)
        13:         {
        14:             return this.ValueProvider.GetValue(prefix).ConvertTo(parameterType);
        15:         }
        16:         if (parameterType.IsArray)
        17:         {
        18:             return BindArrayModel(parameterType, prefix);
        19:         }
        20:         object model = CreateModel(parameterType);
        21:         Type dictionaryType = ExtractGenericInterface(parameterType, typeof(IDictionary<,>));
        22:         if (null != dictionaryType)
        23:         {
        24:             return BindDictionaryModel(prefix, model, dictionaryType);
        25:         }
        26:  
        27:         Type enumerableType = ExtractGenericInterface(parameterType, typeof(IEnumerable<>));
        28:         if (null != enumerableType)
        29:         {
        30:             return BindCollectionModel(prefix, model, enumerableType);
        31:         }
        32:         foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(parameterType))
        33:         {                
        34:             string key = prefix == "" ? property.Name : prefix + "." + property.Name;
        35:             property.SetValue(model, BindModel(property.PropertyType, key));
        36:         }
        37:         return model;
        38:     }
        39:     
        40:     private object BindDictionaryModel(string prefix, object model, Type dictionaryType)
        41:     {
        42:         List<KeyValuePair<object, object>> list = new List<KeyValuePair<object, object>>();
        43:         bool numericIndex;
        44:         IEnumerable<string> indexes = GetIndexes(prefix, out numericIndex);
        45:         Type[] genericArguments = dictionaryType.GetGenericArguments();
        46:         Type keyType = genericArguments[0];
        47:         Type valueType = genericArguments[1];
        48:  
        49:         foreach (var index in indexes)
        50:         {
        51:             string indexPrefix = prefix + "[" + index + "]";
        52:             if (!this.ValueProvider.ContainsPrefix(indexPrefix) && numericIndex)
        53:             {
        54:                 break;
        55:             }
        56:             string keyPrefix = indexPrefix + ".Key";
        57:             string valulePrefix = indexPrefix + ".Value";
        58:             list.Add(new KeyValuePair<object, object>(BindModel(keyType, keyPrefix), BindModel(valueType, valulePrefix)));
        59:         }
        60:         if (list.Count == 0)
        61:         {
        62:             return null;
        63:         }
        64:         ReplaceHelper.ReplaceDictionary(keyType, valueType, model, list);
        65:         return model;
        66:     }    
        67: }

      在BindDictionaryModel方法中,我們采用與數組/集合綁定一樣的方式調用GetIndexes方法得到索引列表。在對該列表進行遍歷過程中,我們在索引的基礎上添加“.Key”和“.Value”后綴從而得到作為字典元素(KeyValuePair<TKey, TValue>)Key和Value對象的前綴,并將該前綴作為參數遞歸地調用BindModel方法得到具體作為Key和Value的對象。在得到字典元素Key和Value之后,我們創建一個KeyValuePair<object, object>對象并添加預先創建的列表中。最后我們調用ReplaceHelper的靜態方法ReplaceDictionary將該列表拷貝到作為Model的字典對象中,ReplaceHelper的靜態方法ReplaceDictionary定義如下。

         1: internal static class ReplaceHelper
         2: {
         3:     //其他成員
         4:     private static MethodInfo replaceDictionaryMethod = typeof(ReplaceHelper).GetMethod("ReplaceDictionaryImpl", BindingFlags.Static |BindingFlags.NonPublic);    
         5:  
         6:     public static void ReplaceDictionary(Type keyType, Type valueType, object dictionary, object newContents)
         7:     {
         8:         replaceDictionaryMethod.MakeGenericMethod(new Type[] { keyType, valueType }).Invoke(null, new object[] { dictionary, newContents });
         9:     }
        10:  
        11:     private static void ReplaceDictionaryImpl<TKey, TValue>(IDictionary<TKey, TValue> dictionary, IEnumerable<KeyValuePair<object, object>> newContents)
        12:     {
        13:         dictionary.Clear();
        14:         foreach (KeyValuePair<object, object> pair in newContents)
        15:         {
        16:             TKey key = (TKey)pair.Key;
        17:             TValue local2 = (TValue)((pair.Value is TValue) ? pair.Value : default(TValue));
        18:             dictionary[key] = local2;
        19:         }
        20:     }
        21: }

      我們照例通過我們創建的實例程序來驗證自定義的DefaultModelBinder是否能夠支持針對字典的Model綁定。如下面的代碼片斷所示,我們讓HomeController的Action方法接受一個IDictionary<string, Contact>類型的參數,并在該方法中將作為Key的字符串和作為Value的Contact的相關信息呈現出來。在GetValueProvider方法中提供的NameValueCollectionValueProvider按照相應的映射規則對綁定到字典對象的數據項。

         1: public class HomeController : Controller
         2: {
         3:     private IValueProvider GetValueProvider()
         4:     {
         5:         NameValueCollection requestData = new NameValueCollection();
         6:         requestData.Add("[0].Key", "Foo");
         7:         requestData.Add("[0].Value.Name", "Foo");
         8:         requestData.Add("[0].Value.PhoneNo", "123456789");
         9:         requestData.Add("[0].Value.EmailAddress", "Foo@gmail.com");
        10:  
        11:         requestData.Add("[1].Key", "Bar");
        12:         requestData.Add("[1].Value.Name", "Bar");
        13:         requestData.Add("[1].Value.PhoneNo", "987654321");
        14:         requestData.Add("[1].Value.EmailAddress", "Bar@gmail.com");
        15:  
        16:         return new NameValueCollectionValueProvider(requestData, CultureInfo.InvariantCulture);
        17:     }
        18:  
        19:     public void Action(IDictionary<string, Contact> contacts)
        20:     {
        21:         foreach (string key  in contacts.Keys)
        22:         {
        23:             Response.Write(key + "<br/>");
        24:             Contact contact = contacts[key];
        25:             Response.Write(string.Format("&nbsp;&nbsp;&nbsp;&nbsp;{0}: {1}<br/>","Name", contact.Name));
        26:             Response.Write(string.Format("&nbsp;&nbsp;&nbsp;&nbsp;{0}: {1}<br/>","PhoneNo", contact.PhoneNo));
        27:             Response.Write(string.Format("&nbsp;&nbsp;&nbsp;&nbsp;{0}: {1}<br/><br/>", "EmailAddress", contact.EmailAddress));
        28:         }
        29:     }
        30: }

      程序運行之后會在瀏覽器中得到如下的我們期望的輸出結果。(S520)

         1: Foo
         2:     Name: Foo
         3:     PhoneNo: 123456789
         4:     EmailAddress: Foo@gmail.com
         5:  
         6: Bar
         7:     Name: Bar
         8:     PhoneNo: 987654321
         9:     EmailAddress: Bar@gmail.com

      通過實例模擬ASP.NET MVC的Model綁定的機制:簡單類型+復雜類型
      通過實例模擬ASP.NET MVC的Model綁定的機制:數組
      通過實例模擬ASP.NET MVC的Model綁定的機制:集合+字典

      posted @ 2012-05-31 08:35  Artech  閱讀(10273)  評論(11)    收藏  舉報
      主站蜘蛛池模板: 中文字幕日韩精品无码内射| 国产精品国产三级国快看| 国产成人AV一区二区三区在线| 精人妻无码一区二区三区| 国产天美传媒性色av高清| 精品超清无码视频在线观看| 亚洲二区中文字幕在线| 99久久激情国产精品| 亚洲一区二区精品偷拍| 中文字幕日韩人妻一区| 人妻少妇精品视频二区| 日本熟妇色xxxxx日本免费看 | 久久精品av国产一区二区| 国产小嫩模无套中出视频| 亚洲天堂亚洲天堂亚洲色图| 极品少妇xxxx| 韩国福利片在线观看播放| 亚洲男女羞羞无遮挡久久丫| 国产普通话对白刺激| 狠狠色婷婷久久综合频道日韩| 国产精品久久久天天影视香蕉| 亚洲中文字幕无码av永久| 激烈的性高湖波多野结衣| 国产精品成人一区二区三区| 在线a亚洲老鸭窝天堂| 成人亚欧欧美激情在线观看| 久久蜜臀av一区三区| 青青青青国产免费线在线观看| 中文字幕无码av波多野吉衣| 国产成人无码综合亚洲日韩| 亚洲精品美女久久久久9999| 亚洲人成在线观看网站不卡| 久久精品国产亚洲精品色婷婷| 久久国产精品第一区二区| 野花社区视频www官网| 亚洲偷自拍另类一区二区| VA在线看国产免费| 成人亚欧欧美激情在线观看| 人妻教师痴汉电车波多野结衣| 精精国产xxx在线观看| 在线观看中文字幕码国产|