ExtJS的store.sync向Asp.net MVC的Action提交时引发System.Reflection.AmbiguousMatchException异常
2013-03-13 16:41
295 查看
ExtJs中的store在sync时,是可以批量提交数据的,所谓的批量是指如果在store中同时记录了create、update、delete的对象时,分三次提交。在提交时,多个对象将被组合成JSON格式的字符串,当要提交的数据只有一条时,JSON的字符串如下所示:
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
如果是多条数据时,JSON的字符串是:
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
在Controller的Action中,如果方法的签名是public JsonResult CreateUser(UserDataObject user),则当传入多条数据时,只能接收到第1条;当方法签名是private List<UserDataObject> ProcessUsers(List<UserDataObject> users)时,当多条数据时没有问题,可只有1条数据时,users为null值。
我想当然的想到在Action中直接把两个方法都写上,但结果报了System.Reflection.AmbiguousMatchException,即MVC的ActionSelector已经不能区分应该调哪个方法了。
经过查找MVC的代码,发现在AsyncActionMethodSelector的RunSelectionFilters方法中,将会查找在Action上的Atrribute,像HttpPost这样的Attribute都会做过滤,以判断是否符合当前调用的上下文。
知道了这一点以后,我试想可以通过写一个自定义的Attribute,然后根据当前Request请求的内容来决定哪个方法可用,哪个方法不可用,实现这个的关键点有两个:
1、如何实现这个Attribute。
2、如何得到Request的Post的内容并进行解决。
第1个问题很好解决,因为我还没有系统的看MVC方面的资料,所以查看一下HttpPost可以知道它继承了ActionMethodSelectorAttribute,这个类里有一个抽象的方法IsValidForRequest。
第2个问题可以得到Request后,然后判断当前Post的类型是否为application/json,进行对Post的数据进行JSON的反序列化。经过测试得知,如果是单一对象的话,反序列化化的对象是一个Dictionay<String,Object>对象,而多个对象得到的是一个Object[]。下面给出实现的源码:
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
需要注意的时,在读取了InputStream后,要重新将Position置为0,否则后续的JsonValueProviderFactory将得不到反序化实例,这样即使能进入到正确的Action,参数也会为空。
下面是Controller中的测试的代码片段:
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
{"ID":"a6d671ca-5480-4b5b-bf7a-b8459c0f598b","MobilePIN":"","Email":"111@ee.com","Password":"","CreateDate":null,"LastLoginDate":null,"LastPasswordChangedDate":null,"Comment":"","UserName":"user1","MobileAlias":"","LastActivityDate":null,"DisplayName":"","RememberMe":false}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
如果是多条数据时,JSON的字符串是:
[{"ID":"a6d671ca-5480-4b5b-bf7a-b8459c0f598b","MobilePIN":"","Email":"111@ee.com","Password":"","CreateDate":null,"LastLoginDate":null,"LastPasswordChangedDate":null,"Comment":"","UserName":"user1","MobileAlias":"","LastActivityDate":null,"DisplayName":"","RememberMe":false}]
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
在Controller的Action中,如果方法的签名是public JsonResult CreateUser(UserDataObject user),则当传入多条数据时,只能接收到第1条;当方法签名是private List<UserDataObject> ProcessUsers(List<UserDataObject> users)时,当多条数据时没有问题,可只有1条数据时,users为null值。
我想当然的想到在Action中直接把两个方法都写上,但结果报了System.Reflection.AmbiguousMatchException,即MVC的ActionSelector已经不能区分应该调哪个方法了。
经过查找MVC的代码,发现在AsyncActionMethodSelector的RunSelectionFilters方法中,将会查找在Action上的Atrribute,像HttpPost这样的Attribute都会做过滤,以判断是否符合当前调用的上下文。
知道了这一点以后,我试想可以通过写一个自定义的Attribute,然后根据当前Request请求的内容来决定哪个方法可用,哪个方法不可用,实现这个的关键点有两个:
1、如何实现这个Attribute。
2、如何得到Request的Post的内容并进行解决。
第1个问题很好解决,因为我还没有系统的看MVC方面的资料,所以查看一下HttpPost可以知道它继承了ActionMethodSelectorAttribute,这个类里有一个抽象的方法IsValidForRequest。
第2个问题可以得到Request后,然后判断当前Post的类型是否为application/json,进行对Post的数据进行JSON的反序列化。经过测试得知,如果是单一对象的话,反序列化化的对象是一个Dictionay<String,Object>对象,而多个对象得到的是一个Object[]。下面给出实现的源码:
public class JsonModelPostAttribute : ActionMethodSelectorAttribute { public enum ParameterType { Single, Multiple } private ParameterType _parameterType; public ParameterType MethodParameterType { get { return _parameterType; } set { _parameterType = value; } } public JsonModelPostAttribute() { _parameterType = ParameterType.Single; } public JsonModelPostAttribute(ParameterType type) { _parameterType = type; } public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo) { var c = GetDeserializedObject(controllerContext); if (c == null) { return true; } if (MethodParameterType == ParameterType.Single) { return c is Dictionary<string, object>; } else { return c is object[]; } } private static object GetDeserializedObject(ControllerContext controllerContext) { if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase)) { // not JSON request return null; } controllerContext.HttpContext.Request.InputStream.Seek(0, SeekOrigin.Begin); StreamReader reader = new StreamReader(controllerContext.HttpContext.Request.InputStream); string bodyText = reader.ReadToEnd(); controllerContext.HttpContext.Request.InputStream.Seek(0, SeekOrigin.Begin); if (String.IsNullOrEmpty(bodyText)) { // no JSON data return null; } JavaScriptSerializer serializer = new JavaScriptSerializer(); object jsonData = serializer.DeserializeObject(bodyText); return jsonData; } }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
需要注意的时,在读取了InputStream后,要重新将Position置为0,否则后续的JsonValueProviderFactory将得不到反序化实例,这样即使能进入到正确的Action,参数也会为空。
下面是Controller中的测试的代码片段:
[AllowAnonymous] [HttpPost] [JsonModelPost(JsonModelPostAttribute.ParameterType.Multiple)] public JsonResult CreateUser(List<UserDataObject> users) { ProcessUsers(users); return this.Json(new { success = true, user = users }, JsonRequestBehavior.AllowGet); } private List<UserDataObject> ProcessUsers(List<UserDataObject> users) { int i = 1; foreach (var user in users) { user.ID = Guid.Empty.ToString(); user.UserName = "Server Name" + i++; } return users; } [AllowAnonymous] [HttpPost] [JsonModelPost(JsonModelPostAttribute.ParameterType.Single)] public JsonResult CreateUser(UserDataObject user) { var list = new List<UserDataObject>(new UserDataObject[] { user }); ProcessUsers(list); return this.Json(new { success = true, user = list[0] }, JsonRequestBehavior.AllowGet); }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
相关文章推荐
- “System.Reflection.AmbiguousMatchException”类型的异常在 mscorlib.dll 中发生
- asp.net mvc 调用C++编写的64位的dll引发System.BadImageFormatException
- ASP.NET MVC中在Action获取提交的表单数据方法总结
- ASP.NET MVC 认证模块报错:“System.Configuration.Provider.ProviderException: 未启用角色管理器功能“
- 无法在Web服务器上启动调试."System.Net.DigestClient"的类型初始值设定项引发异常,Unable to debug System.Net.DigestClient throws an exception
- .net System.TypeInitializationException 类型初始值设定项引发异常
- 对ASP.NET网站执行代码覆盖率测试发生System.Security.VerificationException异常的解决方案
- ASP.NET MVC中在Action获取提交的表单数据方法总结
- ASP.NET异常具体信息: System.IndexOutOfRangeException: 索引 0 不是为负数,就是大于行数。
- [VB.NET]求助:::ServerVersion = “sqlconn.ServerVersion”引发了“System.InvalidOperationException”类型的异常
- 让asp.net mvc的Action支持jQuery直接提交的javascript对象
- ASP.NET MVC 认证模块报错:“System.Configuration.Provider.ProviderException: 未启用角色管理器功能“
- asp.net Chartr控件异常: System.Web.HttpException: 为 ChartImg.axd 执行子请求时出错(已解决)
- ASP.NET中异常详细信息: System.Security.SecurityException: 不允许所请求的注册表访问权
- 让windows日志记录web程序的异常-EnterpriseLibrary.ExceptionHandling在asp.net mvc中的初步应用
- ASP.NET MVC 认证模块报错:“System.Configuration.Provider.ProviderException: 未启用角色管理器功能“
- ASP.NET MVC中在Action获取提交的表单数据方法
- ASP.NET MVC ajax 提交列表到 Action
- 【ASP.NET 问题】System.InvalidOperationException: 对象的当前状态使该操作无效 【大量表单数据提交】错误解决
- C# B/S程序中出现“异常详细信息: System.Data.SqlClient.SqlException: 用户 'XXX/ASPNET' 登录失败。”的处理方法