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

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

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必须填写")]
public string ChildId { get; set; }
}
并为类ReceiverInfo增加一个属性public List ReceiverInfoChild { get; set; }
我们把JsonValueProviderFactory拿出来放在项目里面,然后在Global.asax里面注册一下,就可以使用了。
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对象,所以我们提交数据的时候需要这样写:
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(ListReceiverInfo> receiverInfo)
看一下调试的结果:

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

至此,我们实验了四种方案:
第一种方案,最麻烦,而且容易出错(可能跟我个人不喜欢拼接字符串有关系);
第二种方案,有一定的通用性,但是不利于数据验证;
第三种方案,通用,可以进行有效的数据验证,应对一般的需求够用了,但是处理更复杂的对象不行;
第四种方案,几乎可以处理我们遇到的所有情况
另外,这是在ASP.NET MVC2中的使用,到了ASP.NET MVC3,微软已经把JsonValueProviderFactory作为内置的功能了。
ASP.NET MVC中的Json Binding和Validate的更多相关文章
- ADO.NET .net core2.0添加json文件并转化成类注入控制器使用 简单了解 iTextSharp实现HTML to PDF ASP.NET MVC 中 Autofac依赖注入DI 控制反转IOC 了解一下 C# AutoMapper 了解一下
ADO.NET 一.ADO.NET概要 ADO.NET是.NET框架中的重要组件,主要用于完成C#应用程序访问数据库 二.ADO.NET的组成 ①System.Data → DataTable, ...
- ASP.NET MVC中controller和view相互传值的方式
ASP.NET MVC中Controller向view传值的方式: ViewBag.ViewData.TempData 单个值的传递 Json 匿名类型 ExpandoObject Cookie Vi ...
- 如何在 ASP.NET MVC 中集成 AngularJS(3)
今天来为大家介绍如何在 ASP.NET MVC 中集成 AngularJS 的最后一部分内容. 调试路由表 - HTML 缓存清除 就在我以为示例应用程序完成之后,我意识到,我必须提供两个版本的路由表 ...
- 如何在 ASP.NET MVC 中集成 AngularJS(2)
在如何在 ASP.NET MVC 中集成 AngularJS(1)中,我们介绍了 ASP.NET MVC 捆绑和压缩.应用程序版本自动刷新和工程构建等内容. 下面介绍如何在 ASP.NET MVC 中 ...
- 超高性能的json序列化之MVC中使用Json.Net
先不废话,直接上代码 Asp.net MVC自带Json序列化 /// <summary> /// 加载组件列表 /// </summary> /// <param na ...
- Asp.net MVC中提交集合对象,实现Model绑定
Asp.net MVC中的Model自动绑定功能,方便了我们对于request中的数据的处理, 从客户端的请求数据,自动地以Action方法参数的形式呈现.有时候我们的Action方法中想要接收数组类 ...
- Asp.net mvc中的Ajax处理
在Asp.net MVC中的使用Ajax, 可以使用通用的Jquery提供的ajax方法,也可以使用MVC中的AjaxHelper. 这篇文章不对具体如何使用做详细说明,只对于在使用Ajax中的一些需 ...
- Ext.Net学习笔记24:在ASP.NET MVC中使用Ext.Net
在前面的笔记中已经介绍了如何在ASP.NET WebForm中使用Ext.Net,由于这个系列一直在WebForm中使用,所以并没有涉及到ASP.NET MVC中的用法. 如果你要在ASP.NET M ...
- MVC中处理Json和JS中处理Json对象
MVC中处理Json和JS中处理Json对象 ASP.NET MVC 很好的封装了Json,本文介绍MVC中处理Json和JS中处理Json对象,并提供详细的示例代码供参考. MVC中已经很好的封装了 ...
随机推荐
- Simple Factory 简单工厂模式(静态工厂)
基本概念: 1) Simple Factory模式属于创建型模式, 2) 简单工厂模式是由一个工厂(注意是一个!)对象决定创建出哪一种产品类的实例(例如你到肯德基说你要鸡腿,要薯条,要饮料还是,,,这 ...
- Orcle数据库编程:一
1.PL/SQL是一种块结构的语言,一个PL/SQL程序包含了一个或者多个逻辑块,逻辑块中可以声明变量,变量在使用之前必须先声明. declare mstu student%ROWTYPE;--定义参 ...
- 243. Shortest Word Distance
题目: Given a list of words and two words word1 and word2, return the shortest distance between these ...
- C++:类的成员函数定义方式
1.成员函数的第一种定义方式:在类声明中只给出成员函数的原型,而将成员函数的定义 放在类的外部. 返回值类型 类名::成员函数名(参数表) { 函数体 } class Point{ pub ...
- Invoke与BeginInvoke
一.为什么 Control类提供了 Invoke和 BeginInvoke机制? 关于这个问题的最主要的原因已经是 dotnet程序员众所周知的,我在此费点笔墨再次记录到自己的日志,以便日后提醒一下自 ...
- 面试题_125_to_133_Java 面试中其他各式各样的问题
这部分包含 Java 中关于 XML 的面试题,JDBC 面试题,正则表达式面试题,Java 错误和异常及序列化面试题 125)嵌套静态类与顶级类有什么区别?(答案)一个公共的顶级类的源文件名称与类名 ...
- Effective C++学习笔记 条款07:为多态基类声明virtual析构函数
一.C++明确指出:当derived class对象经由一个base class指针被删除,而该base class带着一个non-virtual析构函数,其结果未定义——实际执行时通常发生的是对象的 ...
- 1346. Intervals of Monotonicity(dp)
1346 简单dp #include <iostream> #include<cstdio> #include<cstring> #include<algor ...
- hdu 4825 Xor Sum (建树) 2014年百度之星程序设计大赛 - 资格赛 1003
题目 题意:给n个数,m次询问,每次给一个数,求这n个数里与这个数 异或 最大的数. 思路:建一个类似字典数的数,把每一个数用 32位的0或者1 表示,查找从高位向底位找,优先找不同的,如果没有不同的 ...
- hdu 1243 反恐训练营(dp 最大公共子序列变形)
题目:http://acm.hdu.edu.cn/showproblem.php?pid=1243 d[i][j] 代表第i 个字符与第 j 个字符的最大的得分.,, 最大公共子序列变形 #inclu ...