通過例項模擬ASP.NET MVC的Model繫結的機制:集合+字典
在本系列的前面兩篇文章(《簡單型別+複雜型別》、《陣列》)我們通過建立的例項程式模擬了ASP.NET MVC預設使用的DefaultModelBinder對簡單型別、複雜型別以及陣列物件的Model繫結。現在我們按照相同的方式來分析基於集合和字典型別的Model繫結是如何實現的。[原始碼從這裡下載][本文已經同步到《How ASP.NET MVC Works?》中]
一、集合
這裡的集合指的是除陣列和字典之外的所有實現IEnumerable<T>介面的型別。和基於陣列的Model繫結類似,ValueProvider可以將多個同名的資料項作為集合的元素,基於索引(基零整數和字串)的資料項命名方式同樣適用
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", "[email protected]");
9:
10: requestData.Add("[1].Name", "Bar");
11: requestData.Add("[1].PhoneNo", "987654321");
12: requestData.Add("[1].EmailAddress", "[email protected]");
13:
14: return new NameValueCollectionValueProvider(requestData, CultureInfo.InvariantCulture);
15: }
16:
17: public void Action(IEnumerable<Contact> contacts)
相關推薦
通過例項模擬ASP.NET MVC的Model繫結機制:簡單型別+複雜型別
總的來說,針對目標Action方法引數的Model繫結完全由元件ModelBinder來實現,在預設情況下使用的ModelBinder型別為DefaultModelBinder,接下來我們將按照逐層深入的方式介紹實現在DefaultModelBinder的預設Model繫結機制。[原始碼從這裡下載][本文已經
通過例項模擬ASP.NET MVC的Model繫結的機制:集合+字典
在本系列的前面兩篇文章(《簡單型別+複雜型別》、《陣列》)我們通過建立的例項程式模擬了ASP.NET MVC預設使用的DefaultModelBinder對簡單型別、複雜型別以及陣列物件的Model繫結。現在我們按照相同的方式來分析基於集合和字典型別的Model繫結是如何實現的。[原始碼從這裡下載][本文已經
ASP.NET 資料繫結概述
使用 ASP.NET 資料繫結,您可以將任何伺服器控制元件繫結到簡單的屬性、集合、表示式和/或方法。如果您使用資料繫結,則當您在資料庫中或通過其他方法使用資料時,您會具有更大的靈活性。本文討論了下列資料繫結主題: 資料繫結概要 <%# %> 語法
ASP.NET資料繫結控制元件
資料繫結控制元件簡介 資料繫結分為:資料來源 和 資料繫結控制元件 兩部分,資料繫結控制元件通過資料來源來獲得資料,通過資料來源來 隔離資料提供者和資料使用者,資料來源有: SqlDataSource,AccessDataSource,ObjectDataSource,L
ASP.Net資料繫結控制元件小結
資料繫結作為ASP.Net中較為重要的一個知識點,其中涉及到了三個重要的資料繫結控制元件,Repeater DataList和GridView(DataGrid)。 Repeater控制元件: 特點: 顧名思義 就是重複繫結資料的控制元件,它沒有內建佈局。
ASP.NET-資料來源繫結
<asp:Label ID="Label1" runat="server" Text='<%# "總金額為:" + Convert.ToString(Convert.ToDecimal(TextBox1.Text)*Convert.ToInt32(TextBox2.Text))%>' /&g
Windows 2008 server + IIS 7 設置身份模擬(ASP.NET impersonation)
oid thead tar level 現在 如果 system out 編輯框 IIS7 與 IIS 6 相比有了很大的改動,原來在 IIS 6 下可以的設置到了 IIS 7 下有的會發生變化。身份模擬的配置上,IIS7 和 IIS6有很大不同,網上IIS6的
Jquery通過append新元素之後事件繫結問題的解決方案:
1、 重複繫結 (DOM載入時,先對DOM中存在的元素進行事件繫結,每次新增的元素時,再對新增元素繫結一次事件) 2、 直接在標籤上新增onclick屬性 3、 事件委託 4、 如果元素是用click事件append進來的,那麼功能函式必須放在這個click事件裡面; 具體程式碼不表,
模擬Vue雙向資料繫結
事件物件 function EventEmit(){ // { // "message":['事件1','事件2'] // } this.callbacks={} } EventEmit.prototype.on=function(eventNa
ASP:Gridview中繫結列的常見格式化字串
如下一段程式碼: <asp:boundField DataField="繫結列" headerText="列名稱" dataFormatString="格式化型別" 常見的格式化型別有: 貨幣 {0:C} 科學計數法(指數) {0:E} 輩分比 {0:P} 固定浮點數
RabbitMQ通過Exchange.Direct、同一個佇列繫結不同的routekey實現不同的消費
通過消費者去進行Exchange和Queue通過不同的RouteKey進行繫結 消費者1: static void Main(string[] args) { ConnectionFactory factory = new ConnectionFacto
android例項 listview與sqlite資料繫結
ListView與Sqlite資料庫繫結步驟: 1.將Sqlite資料庫的內容查詢出來並放入陣列列表中,形成ListView的資料來源; 2.介面卡繫結資料來源,顯示在ListView item中。 本文實現的ListView與Sqlite資料繫結的功能如下圖-1
通過擴充套件讓ASP.NET Web API支援JSONP
同源策略(Same Origin Policy)的存在導致了“源”自A的指令碼只能操作“同源”頁面的DOM,“跨源”操作來源於B的頁面將會被拒絕。同源策略以及跨域資源共享在大部分情況下針對的是Ajax請求。同源策略主要限制了通過XMLHttpRequest實現的Ajax請求
Android中通過Tag為View儲存資料繫結資料
專案中有時候需要為View繫結資料,比如每一個雲標籤都對應伺服器一個標籤id,View中setTag可以方便的為控制元件繫結資料。 為控制元件繫結資料: selectCategory.setTag(R.id.tag_id, id); selectCategory.setT
android例項 listview與sqlite資料繫結
ListView與Sqlite資料庫繫結步驟: 1.將Sqlite資料庫的內容查詢出來並放入陣列列表中,形成ListView的資料來源; 2.介面卡繫結資料來源,顯示在ListView item中。 本文實現的ListView與Sqlite資料繫結的
.NET資料繫結說明和使用方法
資料繫結對被繫結物件有特殊要求,如果只是普通的get;set屬性的物件用在資料繫結上無法雙向繫結(只有Model值不會變或者Model變了不要求介面跟著變才可以使用普通屬性), 一般要求類實現InotifyPropertyChanged介面 INotifyProperty
Jquery通過append新元素之後事件繫結問題的解決方案
昨天在專案中發現一個問題:在DOM載入之後為標籤繫結的事件對於新加進來的標籤並不起作用,通過查詢發現事件並沒有繫結到新加入的標籤,因此今天特意總結一下這種問題的解決方案。 在jquery中,我們通常是在DOM載入完成後,再對元素繫結事件。以下面的情景為例:製作
.NET資料繫結時BoundField與TemplateField的區別
在.NET中,資料繫結列是通過 asp:BoundField 或 TemplateField 元素定義的。通過設定 DataField 屬性,可以將 BoundField 繫結到 GridView
通過偽靜態規則實現子目錄繫結
如果根目錄也繫結其它域名的話,可以通過子目錄訪問子站,就會導致子站檔案多出個訪問URL,建議不要在根目錄繫結其它域名;當然,如果繫結子目錄都是一級目錄subDomain下的子目錄,可以通過robots.txt禁止收錄subDomain目錄,這樣就不用擔心上面的問題了。可以使用DisallowDirdh88
ASP.NET MVC5路由系統機制詳細講解
提交 eas 找文件 網址 自動調用 提取 ges pri stat 請求一個ASP.NET mvc的網站和以前的web form是有區別的,ASP.NET MVC框架內部給我們提供了路由機制,當IIS接受到一個請求時,會先看是否請求了一個靜態資源(.html,css,js