日期:2014-05-17  浏览次数:21088 次

ASP.NET MVC中的Json Binding和Validate

引子:电子商务网站支付功能页面往往会有很多信息,对于这些信息的保存,往往是分步完成的,那么使用Ajax最合适不过了,比如其中的收货人信息模块。这些信息的新建和编辑保存都是用Ajax来完成的。那么有几种方式完成这个操作呢,我想到如下几种。
先来看看该功能的截图:



1、将需要的值拼接成json文本,再Action里面处理

?

首先您需要将要保存的值拼接成一个json文本,类似:

var test = "{ ReceiverId: 5, ReceiverName: 'will', Sex: 'F', CreateDate: '2011-02-21' }";

然后用Jquery保存到数据库,代码如下:


$.ajax({
??? url: "/Home/test1",
??? type: "post",
??? cache: false,
??? data: test
});

然后您在Action里面这样操作:

StreamReader reader = new StreamReader(Request.InputStream);
string bodyText = reader.ReadToEnd();
JavaScriptSerializer js = new JavaScriptSerializer();
ReceiverInfo receiver = js.DeserializeReceiverInfo>(bodyText);
//保存。。。

2、利用自定义的ModelBinder实现


JsonBinder

1 public class JsonBinderT> : IModelBinder
2 {
3???? public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
4???? {
5???????? StreamReader reader = new StreamReader(controllerContext.HttpContext.Request.InputStream);
6???????? string json = reader.ReadToEnd();
7
8???????? if (string.IsNullOrEmpty(json))
9???????????? return json;
10
11???????? JavaScriptSerializer serializer = new JavaScriptSerializer();
12???????? object jsonData = serializer.DeserializeObject(json);
13???????? return serializer.DeserializeT>(json);
14???? }
15 }


我们继承IModelBinder接口,实现其方法:

public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)

即可。我们可以在Action里面这样使用:


public ActionResult Test1([ModelBinder(typeof(JsonBinderReceiverInfo>))] ReceiverInfo receiverInfo)

这样我们自定义的IModelBinder就会取代DefaultModelBinder完成数据绑定。

3、直接传递一个Json对象

?

上面两种方法并没有利用MVC的System.ComponentModel.DataAnnotations进行有效的数据验证。您可能需要自己手动验证,无疑增加了工作量。

我们试试这种方式。

前端的写法:

var b = {
??? ReceiverId: 5,
??? ReceiverName: "will",
??? Sex: "F",
??? CreateDate: "2011-02-21"
};
$.ajax({
??? url: "/Home/test1",
??? type: "post",
??? cache: false,
??? data: b,
??? success: function(data) { alert(data.message); },
??? error: function(xhr, a, b) { alert(xhr.responseText); }
});


Action的写法:


public ActionResult Test1(ReceiverInfo receiverInfo)

我们能正常的得到绑定后的数据。而且我们还能利用System.ComponentModel.DataAnnotations进行数据验证。我们为ReceiverInfo做如下改动:


[System.ComponentModel.DataAnnotations.Required(ErrorMessage = "收货人必须填写")]
public string ReceiverName { get; set; }

并在前端为ReceiverName赋值为空字符串,再次执行,得到提示:


很好,不过我们有新的要求了,那就是传递更复杂的对象,比如对象套嵌对象,对象有集合属性,这种方式不能胜任了。


4、利用MvcFutures的JsonValueProviderFactory


每一版的MVC都有一个MvcFutures,里面会有一些额外的功能,这些功能有些会加入下一个版本中,而这些功能在某些时候很有用处。我查看了里面的类,发现有一个类JsonValueProviderFactory正是处理复杂对象的提交和数据验证。由于json对象需要特定解析才能使用默认的DefaultModelBinder,而这个解析过程需要在ValueProvider阶段完成,所以需要实现特定的ValueProvider给DefaultModelBinder。我们需要实现一个ValueProviderFactory和IValueProvider,而MVC里面的DictionaryValueProvider(继承了IValueProvider)已经足够使用了,所以只需要继承ValueProviderFactory实现其方法:public override IValueProvider GetValueProvider(ControllerContext controllerContext)即可,具体代码您可以看JsonValueProviderFactory。

我们定义另一个类:

ReceiverInfoChild

public class ReceiverInfoChild
{
??? [System.ComponentModel.DataAnnotations.Required(ErrorMessage = "ChildId必须填写&quo