您的位置:首页 > 编程语言 > ASP

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的字符串如下所示:

{"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; }
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐