使用反射來通過ASP.NET MVC中的FormCollection自動填充DTO

Coordinator
Aug 24, 2011 at 9:54 AM

因為強類型的諸多好處,在項目中我沒有使用集合的方式創建DTO,而是使用了多個類。但是這樣產生了個非常頭痛的問題:從MVC的FormCollection中傳遞過來的數據,難道要一行一行的碼么…人間地獄呀…本來可以使用UpdateModel()方法,可是我的DTO中有自定義的結構或類類型屬性。這樣的東西該怎么填充?

沒辦法,還是自力更生吧…於是首先要建立一個約定:如何為表單中,用戶結構或類類型的屬性命名?
我在項目文檔的命名約定中注明,用戶結構或類類型的成員在表單中的ID必須使用“.”來分隔。“.”前為DTO中的屬性,“.”後為屬性的成員。

 

這樣一搞就好辦多了。一個泛型方法基本搞定全部問題:

 

<!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--> 1 /// <summary>
2  /// 使用已填充好的FormCollection對象來對DTO進行填充。
3  /// </summary>
4  /// <typeparam name="TDto">DTO類。</typeparam>
5  /// <param name="collection">FormCollection對象。</param>
6  /// <returns>填充好的DTO對象。</returns>
7 /// <exception cref="System.ArgumentNullException">傳入參數不能為空。</exception>
8 public TDto FillDto<TDto>(FormCollection collection)
9 where TDto : class
10 {
11 if (null == collection)
12 throw new ArgumentNullException();
13
14 TDto dto = Activator.CreateInstance<TDto>();
15 Type t = typeof(TDto);
16 Type tObj = null;
17 PropertyInfo propertyInfo, propertyInfoObj;
18
19 foreach (var key in collection.AllKeys)
20 {
21 try
22 {
23 if (key.Contains('.'))
24 {
25 propertyInfo = t.GetProperty(key.Substring(0, key.IndexOf('.')));
26 tObj = propertyInfo.PropertyType;
27
28 var obj = propertyInfo.GetValue(dto, null);
29 propertyInfoObj = tObj.GetProperty(key.Substring(key.IndexOf('.') + 1));
30
31 base.SetPropertyValue(obj, propertyInfoObj, collection[key]);
32
33 propertyInfo.SetValue(dto, obj, null);
34 }
35 else
36 {
37 propertyInfo = t.GetProperty(key);
38
39 base.SetPropertyValue(dto, propertyInfo, collection[key]);
40 }
41 }
42 catch (NullReferenceException)
43 {
44 //throw;
45 //FormCollection中的Key在DTO中未找到的情況。
46 }
47 }
48
49 return dto;
50 }

 

 

唯一需要注意的地方是獲取結構或類類型屬性成員的地方。首先通過PropertyInfo.PropertyType屬性獲取此屬性的Type對象,之後用PropertyInfo.GetValue()方法獲取屬性的實例,這樣一來,就和處理其他成員沒什麼區別了。
這個方法只要稍加修改就可以對所有集合操作而不僅僅是FormCollection。

以下是基類中的SetPropertyValue()方法:

 

<!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--> 1 /// <summary>
2 /// 根據對象的屬性名稱,
3 /// 選擇合適的轉換方式。
4 /// </summary>
5 /// <param name="obj">將要設定值的對象。</param>
6 /// <param name="property">設定值對象的PropertyInfo對象。</param>
7 /// <param name="value">將要設定的值。</param>
8 protected void SetPropertyValue(Object obj, PropertyInfo property, string value)
9 {
10 if ("Guid" == property.PropertyType.Name)
11 {
12 property.SetValue(
13 obj,
14 new Guid(value),
15 null
16 );
17 }
18 else
19 {
20 property.SetValue(
21 obj,
22 Convert.ChangeType(value, property.PropertyType),
23 null
24 );
25 }
26 }

這下可以偷懶了,哈哈哈!

=======================================
Creative Commons License
CC: 署名-非商业性使用-禁止演绎 2.5 中国大陆
=======================================

Rayless,
and pathless,
and the icy earth,
Swung blind
and blackening
in the moonless air.
分类: ASP.NET
标签: Asp.net, C#