在向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
是唯一的选择吗?
答案 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-Type
是application\json
,那么JsonValueProviderFactory
用于构建字典,而字典又使用JavaScriptSerializer()
来反序列化请求,但这会引发异常,因为重复(不区分大小写)键。您可以编写自定义JavaScriptConverter
来处理此问题,但我不确定这是否合适,因为值提供程序与模型绑定程序一起使用以构建模型,并且您的模型不能同时包含两个属性{{ 1}}和foo
(除非您打算将FOO
和foo
映射到其他已知模型属性,否则可能。)
您可以阅读FOO
Request.InputStream
并使用[HttpPost]
public ActionResult YourMethod()
{
StreamReader reader = new StreamReader(Request.InputStream);
string body = reader.ReadToEnd(); // returns "foo=1&FOO=2"
创建一个键/值对数组