ASP.NET MVC中的Json Binding和Validate

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

先来看看该功能的截图:

2011022821271340.jpg

一般情况下这些信息会对应一个实体类,就命名为:ReceiverInfo,简单起见,我定义ReceiverInfo如下:

2011022821411938.jpg


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.Deserialize < ReceiverInfo > (bodyText);
// 保存。。。


2、利用自定义的ModelBinder实现

ContractedBlock.gifExpandedBlockStart.gifJsonBinder
1 public class JsonBinder<T> : 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.Deserialize<T>(json);
14 }
15 }
我们继承IModelBinder接口,实现其  方法:
 
  
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)

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

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

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


3、直接传递一个Json对象

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

我们试试这种方式。

前端的写法:

ContractedBlock.gif ExpandedBlockStart.gif
 
   
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赋值为空字符串,再次执行,得到提示:

2011030111160916.png

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


4、利用MvcFutures的JsonValueProviderFactory

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

我们定义另一个类:

ContractedBlock.gif ExpandedBlockStart.gif ReceiverInfoChild
 
   
public class ReceiverInfoChild
{
[System.ComponentModel.DataAnnotations.Required(ErrorMessage
= " ChildId必须填写 " )]
public string ChildId { get ; set ; }
}
并为类ReceiverInfo增加一个属性public List<ReceiverInfoChild> ReceiverInfoChild { get; set; }

我们把JsonValueProviderFactory拿出来放在项目里面,然后在Global.asax里面注册一下,就可以使用了。

ContractedBlock.gif ExpandedBlockStart.gif
 
   
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();

RegisterRoutes(RouteTable.Routes);

ValueProviderFactories.Factories.Add(
new JsonValueProviderFactory());
}

因为JsonValueProviderFactory中有:if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))来判断进来的请求是不是json对象,所以我们提交数据的时候需要这样写:

ContractedBlock.gif ExpandedBlockStart.gif
 
   
var ReceiverInfo = [
{
ReceiverInfoChild: [{ ChildId:
" 1 " }, { ChildId: " 11 " }],
ReceiverId:
5 ,
ReceiverName:
" will " ,
Sex:
" F " ,
CreateDate:
" 2011-02-21 "
},
{
ReceiverInfoChild: [{ ChildId:
" 2 " }, { ChildId: " 22 " }],
ReceiverId:
5 ,
ReceiverName:
" will " ,
Sex:
" F " ,
CreateDate:
" 2011-02-21 "
}
];
$.ajax({
url:
" /Home/test1 " ,
type:
" post " ,
cache:
false ,
contentType:
" application/json;charset=utf-8 " ,
data: JSON.stringify(ReceiverInfo),
success:
function (data) { alert(data.message); },
error:
function (xhr, a, b) { alert(xhr.responseText); }
});

其中JSON.stringify(ReceiverInfo)是将json对象转换成字符串,您可以到这里下载该类库。

在Action里面,我们这样写就可以了:

 
  
public ActionResult Test1(List < ReceiverInfo > receiverInfo)

看一下调试的结果:

2011030112304214.png

完全正常绑定了值。我们再看看数据验证:

2011030112342419.png


至此,我们实验了四种方案:

第一种方案,最麻烦,而且容易出错(可能跟我个人不喜欢拼接字符串有关系);

第二种方案,有一定的通用性,但是不利于数据验证;

第三种方案,通用,可以进行有效的数据验证,应对一般的需求够用了,但是处理更复杂的对象不行;

第四种方案,几乎可以处理我们遇到的所有情况

另外,这是在ASP.NET MVC2中的使用,到了ASP.NET MVC3,微软已经把JsonValueProviderFactory作为内置的功能了。

转载于:https://www.cnblogs.com/WillMeng/archive/2011/03/01/json_binding_validate.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值