C# JsonValueProviderFactory:System.ArgumentException:已添加具有相同键的项

C# JsonValueProviderFactory:System.ArgumentException:已添加具有相同键的项,c#,asp.net-mvc,rest,log4net,elmah.mvc,C#,Asp.net Mvc,Rest,Log4net,Elmah.mvc,我有一个用于Shopify的webhook api处理程序,它使用json主体调用下面的控制器操作。它立即失败,因为除了OnException方法中出现以下错误的log4net日志之外,没有访问和记录任何log4net日志 问题1: Controllers.ShopWebhooksController.OnException(C:\inetpub\wwwroot\Controllers\ShopWebhooksController.cs:44) System.ArgumentException:

我有一个用于Shopify的webhook api处理程序,它使用json主体调用下面的控制器操作。它立即失败,因为除了
OnException
方法中出现以下错误的log4net日志之外,没有访问和记录任何log4net日志

问题1:

Controllers.ShopWebhooksController.OnException(C:\inetpub\wwwroot\Controllers\ShopWebhooksController.cs:44)
System.ArgumentException: 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.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.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__DisplayClass3_1.<BeginInvokeAction>b__0(AsyncCallback asyncCallback, Object asyncState)
       at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`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.<BeginExecuteCore>b__152_0(AsyncCallback asyncCallback, Object asyncState, ExecuteCoreState innerState)
       at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid`1.CallBeginDelegate(AsyncCallback callback, Object callbackState)
       at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.Begin(AsyncCallback callback, Object state, Int32 timeout)
       at System.Web.Mvc.Controller.BeginExecuteCore(AsyncCallback callback, Object state)
       at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.Begin(AsyncCallback callback, Object state, Int32 timeout)
       at System.Web.Mvc.Controller.BeginExecute(RequestContext requestContext, AsyncCallback callback, Object state)
       at System.Web.Mvc.MvcHandler.<>c.<BeginProcessRequest>b__20_0(AsyncCallback asyncCallback, Object asyncState, ProcessRequestState innerState)
       at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid`1.CallBeginDelegate(AsyncCallback callback, Object callbackState)
       at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.Begin(AsyncCallback callback, Object state, Int32 timeout)
       at System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state)
       at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
       at System.Web.HttpApplication.<>c__DisplayClass285_0.<ExecuteStepImpl>b__0()
       at System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep step)
       at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
Elmah日志中的堆栈跟踪没有帮助,因为它没有深入到足以显示代码中哪一行产生了错误。为什么会这样?我在
async
错误中注意到了这一点……它们似乎更难确定代码中的根本原因行。也许我现在应该把它变成一个同步方法?也许我应该去掉
OnException
方法,因为它可能会掩盖更多信息

问题2:

Controllers.ShopWebhooksController.OnException(C:\inetpub\wwwroot\Controllers\ShopWebhooksController.cs:44)
System.ArgumentException: 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.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.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__DisplayClass3_1.<BeginInvokeAction>b__0(AsyncCallback asyncCallback, Object asyncState)
       at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`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.<BeginExecuteCore>b__152_0(AsyncCallback asyncCallback, Object asyncState, ExecuteCoreState innerState)
       at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid`1.CallBeginDelegate(AsyncCallback callback, Object callbackState)
       at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.Begin(AsyncCallback callback, Object state, Int32 timeout)
       at System.Web.Mvc.Controller.BeginExecuteCore(AsyncCallback callback, Object state)
       at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.Begin(AsyncCallback callback, Object state, Int32 timeout)
       at System.Web.Mvc.Controller.BeginExecute(RequestContext requestContext, AsyncCallback callback, Object state)
       at System.Web.Mvc.MvcHandler.<>c.<BeginProcessRequest>b__20_0(AsyncCallback asyncCallback, Object asyncState, ProcessRequestState innerState)
       at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid`1.CallBeginDelegate(AsyncCallback callback, Object callbackState)
       at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.Begin(AsyncCallback callback, Object state, Int32 timeout)
       at System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state)
       at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
       at System.Web.HttpApplication.<>c__DisplayClass285_0.<ExecuteStepImpl>b__0()
       at System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep step)
       at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
在执行任何代码之前,在点击控制器操作时,什么可能会立即导致此错误?此控制器继承asp.net mvc
控制器
,构造函数中的唯一代码是创建
DBContext
log4net
\u记录器
的实例

堆栈跟踪:

Controllers.ShopWebhooksController.OnException(C:\inetpub\wwwroot\Controllers\ShopWebhooksController.cs:44)
System.ArgumentException: 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.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.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__DisplayClass3_1.<BeginInvokeAction>b__0(AsyncCallback asyncCallback, Object asyncState)
       at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`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.<BeginExecuteCore>b__152_0(AsyncCallback asyncCallback, Object asyncState, ExecuteCoreState innerState)
       at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid`1.CallBeginDelegate(AsyncCallback callback, Object callbackState)
       at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.Begin(AsyncCallback callback, Object state, Int32 timeout)
       at System.Web.Mvc.Controller.BeginExecuteCore(AsyncCallback callback, Object state)
       at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.Begin(AsyncCallback callback, Object state, Int32 timeout)
       at System.Web.Mvc.Controller.BeginExecute(RequestContext requestContext, AsyncCallback callback, Object state)
       at System.Web.Mvc.MvcHandler.<>c.<BeginProcessRequest>b__20_0(AsyncCallback asyncCallback, Object asyncState, ProcessRequestState innerState)
       at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncVoid`1.CallBeginDelegate(AsyncCallback callback, Object callbackState)
       at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.Begin(AsyncCallback callback, Object state, Int32 timeout)
       at System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state)
       at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
       at System.Web.HttpApplication.<>c__DisplayClass285_0.<ExecuteStepImpl>b__0()
       at System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep step)
       at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
我所做的代码更改如下。我确实按照下面提供的答案添加了我自己的
JsonValueProviderFactory
类,但没有提供的是要进行的确切更改……因为这取决于您希望如何处理它。在我的例子中,此更改会导致丢弃任何同名的后续键。因此,如果您想以不同的方式处理它,您需要按照自己的意愿解决:

/// <summary>
/// Modified this to handle duplicate keys
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
public void Add(string key, object value)
{
    if (++_itemCount > _maximumDepth)
    {
        throw new InvalidOperationException("The JSON request was too large to be deserialized.");
    }

    // Add the following if block so if the key already exists, just return instead of trying to add it to the dictionary which will throw an error.
    if (_innerDictionary.ContainsKey(key))
    {
        return;
    }

    _innerDictionary.Add(key, value);
}
//
///修改此选项以处理重复的密钥
/// 
/// 
/// 
公共void添加(字符串键、对象值)
{
如果(++\u itemCount>\u maximumDepth)
{
抛出新的InvalidOperationException(“JSON请求太大,无法反序列化。”);
}
//添加下面的if块,这样如果密钥已经存在,只需返回,而不是尝试将其添加到字典中,这将引发错误。
if(_innerDictionary.ContainsKey(键))
{
返回;
}
_添加(键、值);
}

我不确定我是否理解您的意思是否正确,但请尝试使用日志记录的附加方法临时包装后台调用,然后尝试捕获:

BackgroundJob.Enqueue(()=>UpdateOrderFromWebhookWithLogging(\u logger,validationResult.Value,storefrontId));
并将此方法添加到控制器:

//我不知道如何编写正确的签名
私有void UpdateOrderFromWebhookWithLogging(_logger,orderSyncAppServ,validationResult.Value,storefrontId)
{
尝试
{
orderSyncAppServ.UpdateOrderFromWebhook(validationResult.Value,storefrontId)
}
捕获(例外情况除外)
{
_记录器错误(ex);
投掷;
}
}

我认为您的设计没有问题,但是您的一个类可能具有重复的属性,这将导致运行时异常

比如说

public int storefrontId {get; set;}
public int StorefrontId {get; set;}
您需要配置log4net来记录您的操作调用。 例如:

编辑 下面是如何使用

这将为您提供如下内容。

此外,我将告诉您重写JSONValueProviderFactoryAddToBackStore方法的步骤。您可以使用它来查找导致此问题的属性

  • 从中获取源代码

  • 添加类MyJsonValueProviderFactory.cs

  • 在Global.asax.cs中的JSONValueProviderFactory之前注册新类

    插入(0,新的MyJsonValueProviderFactory())

  • 或者先去掉原稿,然后用你的

    ValueProviderFactories.Factories.Remove(ValueProviderFactories.Factories.OfType<JsonValueProviderFactory>().FirstOrDefault());
    ValueProviderFactories.Factories.Add(new MyJsonValueProviderFactory());
    
    valueProviderFactorys.Factories.Remove(valueProviderFactorys.Factories.OfType().FirstOrDefault());
    valueProviderFactorys.Factories.Add(新的MyJsonValueProviderFactory());
    
    使用异常捕获来处理这个类,您将能够找到问题所在,您可以从EntryLimitedDictionary类中的Add方法开始

    再次使用下面的链接全局注册错误处理。

    它看起来像是JsonValueProviderFactory。AddToBackStore正在遍历JSON输入并将每个叶值放入字典中。字典的键是叶节点的路径。如果遍历遇到具有相同路径的两个叶节点,则会发生该异常

    我认为您需要检查JSON输入数据——可能它有重复的键。例如,这是有效的JSON:

    {
        "id": 1,
        "name": "Some Name"
    }
    
    鉴于这不是:

    {
        "id": 1,
        "name": "Some Name",
        "id": 2
    }
    

    因为“id”键出现多次。这可能会导致您看到的错误。

    好的,我已经将其放入,我将监视以查看并让您知道。不幸的是,这不起作用,此错误仍然没有被捕获,并且正在被Elmah捕获。它不应该被捕获,因为它在后台执行,但它应该记录任何细节,因为你想要什么是你的hangfire配置?。一台服务器一个数据库?@cdev hangfire在同一台服务器上运行,但有一个单独的数据库。仅供参考,我更新了问题以反映新信息,因为我已经缩小了范围。很可能是JSON负载的问题。看看这个答案:@xcskilab这正是我所想的,因为它依赖于数据,因为这个操作的大多数JSON帖子都可以正常工作,只有少数几个会导致问题。现在,我只需要找到一种方法,在错误发生之前捕获它,这样我就可以向我和Shopify证明它!这不仅仅是一个(甚至两个)问题。谢谢你的想法。几乎我要做的第一件事就是在action方法中记录调用:
    \u logger.Debug($“Shopify{webhook}request received”)而这不会被击中。我如何像你提到的那样在更高的级别上登录?此外,由于它在任何逻辑完成之前就失败了,所以不确定哪个类可能具有重复的属性名,因为它甚至从未访问
    
    ValueProviderFactories.Factories.Remove(ValueProviderFactories.Factories.OfType<JsonValueProviderFactory>().FirstOrDefault());
    ValueProviderFactories.Factories.Add(new MyJsonValueProviderFactory());
    
    {
        "id": 1,
        "name": "Some Name"
    }
    
    {
        "id": 1,
        "name": "Some Name",
        "id": 2
    }