2016-03-14 34 views
0

我们开始在我们的日志中看到这个,有什么想法从哪里开始寻找问题?调用堆栈中没有任何东西可以帮助我们开始。JsonValueProvider从MVC应用程序抛出错误

Message :An item with the same key has already been added. at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource) at 
System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean 
add) at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value) at 
System.Web.Mvc.JsonValueProviderFactory.EntryLimitedDictionary.Add(String key, 
Object value) 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.AddToBackingStore(EntryLimitedDictionary backingStore, String prefix, Object value) 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.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.<>c__DisplayClassc.<GetValueProvider>b__7(ValueProviderFactory factory) at 
System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext() at 
System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext() at 
System.Collections.Generic.List`1..ctor(IEnumerable`1 collection) at 
System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source) 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__DisplayClass25. 
<BeginInvokeAction>b__1e(AsyncCallback asyncCallback, Object asyncState) at 
System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.Begin(AsyncCallback callback, Object state, Int32 timeout) at 
System.Web.Mvc.Async.AsyncControllerActionInvoker.BeginInvokeAction(ControllerContext controllerContext, String actionName, AsyncCallback callback, Object 
state) at System.Web.Mvc.Controller.<>c__DisplayClass1d.<BeginExecuteCore>b__17(AsyncCallback asyncCallback, Object asyncState) at 
System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.Begin(AsyncCallback callback, Object state, Int32 timeout) at 
System.Web.Mvc.Controller.BeginExecuteCore(AsyncCallback callback, Object state) at 
System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.Begin(AsyncCallback callback, Object state, Int32 timeout) at 
System.Web.Mvc.Controller.BeginExecute(RequestContext requestContext, AsyncCallback callback, Object state) at 
System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.BeginExecute(RequestContext requestContext, AsyncCallback callback, Object state) at 
System.Web.Mvc.MvcHandler.<>c__DisplayClass8.<BeginProcessRequest>b__2(AsyncCallback asyncCallback, Object asyncState) at 
System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.Begin(AsyncCallback callback, Object state, Int32 timeout) at 
System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state) at 
System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state) at 
System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData) at 
System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) 
+0

'DefaultModelBinder'调用'JsonValueProviderFactory'来将json转换为可用于绑定到您的模型的字典。你知道这是发生在哪个控制器方法(和相关的ajax调用)吗?最好的猜测是这是一些无效的JSON。 –

+0

@StephenMuecke谢谢Stephen。我们有几个我们期待JSON的地方。任何想法为什么在我们的应用程序的callstack没有什么?或者如果我们能够在这个阶段捕获被调用的控制器的任何想法? – MBen

+1

我希望在调用堆栈中看到一些指示控制器/操作方法的东西,所以我有点困惑。 –

回答

2

当您的控制器方法接收JSON,所述DefaultModelBinder使用JsonValueProviderFactory,其使用JavaScriptSerializer反序列化JSON字符串和添加的名称/值对,其被传递给DictionaryValueProvider这又提供用于结合值的字典。造成

你的错误,因为你的JSON包含重复的属性名称的对象,例如{ name: someValue, NAME: anotherValue }所以一旦name: someValue已添加到字典中,加入NAME: anotherValue抛出,因为重复的(不区分大小写)键的例外。这很有意义,因为模型不能包含具有相同名称的两个属性。

而最好的解决方案将是追查和纠正“无效” JSON的来源,你可以写自己的ValueProvideFactory绑定只有第一个值,并使用相同的密钥忽略后续值。为了节省重新发明轮子使用以下步骤:

  1. 复制JsonValueProviderFactory.cs source code的源代码到你的项目
  2. 重命名的命名空间(比如yourProject.ValueProviderFactories)和 添加using System.Web.Mvc;声明
  3. 重命名类(比方说InvalidJsonValueProviderFactory
  4. 修改内部的private class EntryLimitedDictionary

    public void Add(string key, object value) 
    { 
        if (++_itemCount > _maximumDepth) 
        { 
         // throw new InvalidOperationException(MvcResources.JsonValueProviderFactory_RequestTooLarge); 
        } 
        // Add the following if block 
        if (_innerDictionary.ContainsKey(key)) 
        { 
         return; 
        } 
        _innerDictionary.Add(key, value); 
    } 
    
  5. 下面的代码
  6. 以下添加到您的global.asax.cs文件

    ValueProviderFactories.Factories.Insert(0, new yourProject.ValueProviderFactories.InvalidJsonValueProviderFactory()); 
    

注意,它需要因为JsonValueProviderFactory已经被添加到工厂的集合,首先加入。

这将防止你的异常,但当然意味着重复属性将被丢弃。如果它的重要,你得到的是重复的,那么你可以考虑更多的修改,以创建具有不同的独特蕴涵键索引一个新的字典条目,例如

private int _index = 0; 
.... 
if (_innerDictionary.ContainsKey(key)) 
{ 
    string invalidKey = string.Format("duplicates[{0}]", _index++); 
    string invalidValue = string.Format("{0}|{1}", key, value); 
    _innerDictionary.Add(invalidKey, invalidValue); 
    return; 
} 

其中index会从零开始,并在每次递增。然后,您可以在方法string[] duplicates中添加一个附加参数,该参数将填充重复值。至少它会帮助调试问题的根源。

+0

备注:在上面的代码中,我注释了'throw new InvalidOperationException(...)'。由于它应该包含在内,因此您需要从[MvcResources.resx源代码](https://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/Properties/)中追踪相关错误消息MvcResources.resx)并添加给你项目(或只是硬编码) –

+0

非常感谢。我们找到了问题的根源。我们在主应用程序上安装webhook,并且我们有一个虚拟应用程序,显然它们运行在同一个AppPool中。 – MBen

0

我想的问题是,当你在插入新字典相同的密钥值,到时候你是不是要检查重点是存在与否,所以当你插入已经存在的键会出现此问题。简单的解决方案就是在插入之前检查密钥是否存在。

// Create Dictionary with two key value pairs. 
var dictionary = new Dictionary<string, int>() 
{ 
    {"mac", 1000}, 
    {"windows", 500} 
}; 

// Use ContainsKey method. To check Linux is exist or not 
if (dictionary.ContainsKey("linux") == false) 
{ 
    dictionary.Add("linux",300);   
} else 
{ 
    Console.WriteLine("linux is already Exist"); 
} 

在上面的例子mac,window和linux是目录的关键。目录有一个规则,它永远不会再添加存在的密钥。所以你必须在添加前检查。

+0

谢谢。然而,不确定这些键是什么,在Callstack中没有任何帮助我找到问题的地方。 – MBen

+0

我更新了我的答案请引用。 –

+0

[JsonValueProviderFactory.cs](https://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/JsonValueProviderFactory.cs)中的私有方法抛出的错误MVC的源代码 - OP不能修改它 –

相关问题