绑定时JSON属性区分大小写

时间:2014-10-25 00:46:33

标签: c# asp.net asp.net-mvc asp.net-mvc-4

在向MVC应用程序提交JSON正文时,我在绑定期间遇到以下异常:

An item with the same key has already been added.

当HTTP主体具有2个以上JSON属性时,会发生这种情况,这些属性依赖于区分大小写的唯一性。 E.g。

{ "foo":1, "FOO":2 }

Content-Type也必须指定为application\json才能发生异常。

我不知道如何阻止这种情况发生。我尝试了自定义IModelBinder但这种情况发生在IModelBinder.BindModel(...)被调用之前。在将请求传递给我之前,这似乎都发生在标准框架代码中。

完整堆栈跟踪:

System.ArgumentException: An item with the same key has already been added.
   at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
   at System.Web.Mvc.JsonValueProviderFactory.AddToBackingStore(EntryLimitedDictionary backingStore, String prefix, Object value)
   at System.Web.Mvc.JsonValueProviderFactory.AddToBackingStore(EntryLimitedDictionary backingStore, String prefix, Object value)
   at System.Web.Mvc.JsonValueProviderFactory.GetValueProvider(ControllerContext controllerContext)
   at System.Web.Mvc.ValueProviderFactoryCollection.GetValueProvider(ControllerContext controllerContext)
   at System.Web.Mvc.ControllerBase.get_ValueProvider()
   at System.Web.Mvc.ControllerActionInvoker.GetParameterValue(ControllerContext controllerContext,     ParameterDescriptor parameterDescriptor)
   at System.Web.Mvc.ControllerActionInvoker.GetParameterValues(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass21.<BeginInvokeAction>b__19(AsyncCallback asyncCallback, Object asyncState)

如果JSON有效负载完全有效,我该如何防止这种情况发生?

修改

我已经阅读了一点,我现在认为问题出在默认IValueProvider而不是活页夹的行为中。我认为如果指定了application\json的内容类型,则值提供程序会自动将JSON属性解析为(不区分大小写)字典,以供ModelBinder之后使用。考虑到我的堆栈跟踪,这更有意义。

我仍然不能100%确定如何适应这一点。为此控制器编写自定义IValueProvider是唯一的选择吗?

1 个答案:

答案 0 :(得分:2)

如果Content-Type不是application\json,那么FormValueProvider用于构建忽略大小写的字典,并将值组合起来,如下所示

[HttpPost]
public ActionResult YourMethod(FormCollection form)
{    
  var fooA= Request.Form["foo"]; // returns "1,2"
  var fooB= Request.Form["FOO"]; // returns "1,2"
  var fooC= Request.Form["FoO"]; // returns "1,2"

如果Content-Typeapplication\json,那么JsonValueProviderFactory用于构建字典,而字典又使用JavaScriptSerializer()来反序列化请求,但这会引发异常,因为重复(不区分大小写)键。您可以编写自定义JavaScriptConverter来处理此问题,但我不确定这是否合适,因为值提供程序与模型绑定程序一起使用以构建模型,并且您的模型不能同时包含两个属性{{ 1}}和foo(除非您打算将FOOfoo映射到其他已知模型属性,否则可能。)

您可以阅读FOO

中的值
Request.InputStream

并使用[HttpPost] public ActionResult YourMethod() { StreamReader reader = new StreamReader(Request.InputStream); string body = reader.ReadToEnd(); // returns "foo=1&FOO=2" 创建一个键/值对数组