Asp.net Mvc Codeplex Preview 5 第三篇 实现Action参数传递繁杂类型 【转】

本文的环境是Asp.net Mvc Codeplex Preview 5

前文提到我们可以使用 Controller中的UpdateModel来获取 繁杂类型

例如

1 UpdateModel(x, Request.Form.AllKeys);

但是这里有些问题,当我们使用Request.Form.AllKeys时,提交的数据中有非x属性时,就会发生错误:

The model of type 'MyModel' does not have a property named 'Name2'.

但是使用

1 UpdateModel(x, new[] {"IDX", "Name"});

这种形式,我们又会觉得它太过麻烦。

其实Asp.net Mvc为我们提供了一种很简单的传递复杂数据的方式,它类似于Monorail中的DataBinder:

我们完全可以通过以下方式来传递数据。例如

view:

1 <%using (Html.Form("home", "about", FormMethod.Post)) {%>

2 <%=Html.TextBox("my.ID")%>

3 <%=Html.TextBox("my.Name")%>

4 <%=Html.SubmitButton()%>

5 <%} %>

controller:

[AcceptVerbs("post")]

public ActionResult About([ModelBinder(typeof(MyModelBinder))]MyModel my) {

ViewData["Title"] =my.Name + my.ID;

return View();

}

这样我们就可以从my中获取到Post过来的值了,这里的关键在于[ModelBinder(typeof(MyModelBinder))]

而 MyModelBinder的实现方法如下

1 using System;

2 using System.Collections.Generic;

3 using System.ComponentModel;

4 using System.Globalization;

5 using System.Linq;

6 using System.Web.Mvc;

7

8 /// <summary>

9 /// 这个类是根据Controller.UpdateModel方法更改而成

10 /// </summary>

11 public class MyModelBinder : IModelBinder{

12 #region IModelBinder 成员

13

14 public object GetValue(ControllerContext controllerContext, string modelName, Type modelType,

15 ModelStateDictionary modelState){

16 object model = Activator.CreateInstance(modelType); //将做为参数的类实例化了

17 IEnumerable<string> keys = modelType.GetProperties().Select(c => c.Name); //得到该对象的属性的名的字符串数组,这里的结果应该为["ID","Name"]

18 string objectPrefix = modelName; //这个就是,我的对象名叫my则会检查 name="my.ID" name="my.Name"的表单字段

19

20 PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(model); //对象的属性的集合

21 var dictionary = new Dictionary<string, PropertyDescriptor>();

22 foreach (string str in keys){

23 //遍历属性的字符串集合即["ID","Name"]

24 if (!string.IsNullOrEmpty(str)){

25 PropertyDescriptor descriptor = properties.Find(str, true);

26 if (descriptor == null){

27 throw new ArgumentException(

28 string.Format(CultureInfo.CurrentUICulture, "无此属性{0},{1}", new object[]{model.GetType().FullName, str}),

29 "modelName");

30 }

31 string str3 = string.IsNullOrEmpty(objectPrefix) ? str : (objectPrefix + "." + str); //将对象名与属性名拼接,如my.ID

32 dictionary[str3] = descriptor;

33 }

34 }

35 foreach (var pair in dictionary){

36 string key = pair.Key;

37 PropertyDescriptor descriptor2 = pair.Value;

38 object obj2 = ModelBinders.GetBinder(descriptor2.PropertyType).GetValue(controllerContext, key,

39 descriptor2.PropertyType, modelState);

40 if (obj2 != null){

41 try{

42 descriptor2.SetValue(model, obj2); //设置属性的值

43 continue;

44 }

45 catch{

46 //如果有使用验证Helepr则会显示在Html.ValidationSummary中

47 string errorMessage = string.Format(CultureInfo.CurrentCulture, "验证失败{0}:{1}", new[]{obj2, descriptor2.Name});

48 string attemptedValue = Convert.ToString(obj2, CultureInfo.CurrentCulture);

49 modelState.AddModelError(key, attemptedValue, errorMessage);

50 continue;

51 }

52 }

53 }

54 return model; //最后 返回这个我们设置完属性的对象

55 }

56

57 #endregion

58 }

这样我们就实现了 用Action的参数传递复杂类型。

当然,如果你连[ModelBinder(typeof(MyModelBinder))]都不想写了,想直接来以下写法,

1 [AcceptVerbs("post")]

2 public ActionResult About(MyModel my) {

3 ViewData["Title"] =my.Name + my.ID;

4 return View();

5 }

这个也是可以的不过你要在Application_Start中添加

ModelBinders.Binders.Add(typeof (MyModel), new MyModelBinder());

来表示二者的绑定关系。