When submitting a JSON body to an MVC application I get the following exception during binding:
An item with the same key has already been added.
This happens when a HTTP body has 2+ JSON properties that rely on case sensitivity for uniqueness. E.g.
{ "foo":1, "FOO":2 }
The Content-Type
must also be specified as application\json
for the exception to occur.
I am not really sure what to do to stop this from happening. I tried a custom IModelBinder
but this occurs before IModelBinder.BindModel(...)
is even called. This all seems to happen in standard framework code before the request gets passed to me.
Full stack trace:
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)
How do I prevent this from occuring given that the JSON payload is perfectly valid?
Edit:
I've read a little more and I now believe the problem is in the behaviour of the default IValueProvider
rather than the binder. I think if a content type of application\json
is specified then the value provider is automatically parsing the JSON properties into a (case insensitive) dictionary for use by the ModelBinder
afterwards. This makes more sense given the stack trace I had.
I am still not 100% sure how to accommodate for this. Is writing a custom IValueProvider
for this controller the only choice here?