简体   繁体   English

MVC 5过滤器中的异步错误处理

[英]Asynchronous error handling in MVC 5 filters

I've made a custom filter attribute extending the HandleErrorAttribute , that catches all exceptions. 我已经创建了一个自定义过滤器属性来扩展HandleErrorAttribute ,它捕获所有异常。

My entire application is built around async architechture, throughout the stack. 我的整个应用程序都是围绕整个堆栈中的异步架构构建的。 This means, that I somehow have to use the OnException(ExceptionContext contect) override asynchronously. 这意味着,我不得不异步使用OnException(ExceptionContext contect)覆盖。 Something like this, would be how I imagined it (Simplified for readability): 像这样的东西,就像我想象的那样(简化了可读性):

public async override void OnException(ExceptionContext context)
{
    base.OnException(context);
    var logId = await LogException(e, httpContext); //LogException calls an async method and returns the ID of the exception, after it has been saved to the database. I this ID in the filterContext, which is why I need the result of the method
}

However, this would result in InvalidOperationException: An asynchronous operation cannot be started at this time. Asynchronous operations may only be started within an asynchronous handler or module or during certain events in the Page lifecycle 但是,这将导致InvalidOperationException: An asynchronous operation cannot be started at this time. Asynchronous operations may only be started within an asynchronous handler or module or during certain events in the Page lifecycle InvalidOperationException: An asynchronous operation cannot be started at this time. Asynchronous operations may only be started within an asynchronous handler or module or during certain events in the Page lifecycle . InvalidOperationException: An asynchronous operation cannot be started at this time. Asynchronous operations may only be started within an asynchronous handler or module or during certain events in the Page lifecycle

I cannot simply call .Result on the task when called synchronously, as this would cause deadlocks. 我不能简单地在同步调用时调用.Result,因为这会导致死锁。

So I guess my question is: How do I create a filter in MVC5, that can log errors asynchronously? 所以我想我的问题是:如何在MVC5中创建一个可以异步记录错误的过滤器?

Since error handling usually is not hot code there are no performance concerns here. 由于错误处理通常不是热代码,因此这里没有性能问题。 Therefore, do what's most convenient to you. 因此,做最方便的事情。

For example, you can block on the task returned from LogException . 例如,您可以阻止从LogException返回的任务。 There are multiple ways you can reliably avoid a deadlock. 有多种方法可以可靠地避免死锁。 A simple way is Task.Run(() => LogException()).Wait(); 一个简单的方法是Task.Run(() => LogException()).Wait(); . This works because the task body runs without a synchronization context. 这是因为任务主体在没有同步上下文的情况下运行。

You also can add ConfigureAwait(false) inside of LogException but you cannot miss a single place. 您还可以在LogException添加ConfigureAwait(false) ,但不能错过任何一个地方。 That makes this brittle. 这使得这很脆弱。

I suggest you to change approach and implement own ExceptionLogger because it's ExceptionLogger job to log exceptions 我建议你改变方法并实现自己的ExceptionLogger,因为它是用于记录异常的ExceptionLogger作业

We provide two new user-replaceable services, IExceptionLogger and IExceptionHandler, to log and handle unhandled exceptions. 我们提供了两个新的用户可替换服务IExceptionLogger和IExceptionHandler来记录和处理未处理的异常。 The services are very similar, with two main differences: We support registering multiple exception loggers but only a single exception handler. 服务非常相似,有两个主要区别:我们支持注册多个异常记录器,但只支持一个异常处理程序。 Exception loggers always get called, even if we're about to abort the connection. 即使我们即将中止连接,也会始终调用异常记录器。 Exception handlers only get called when we're still able to choose which response message to send. 只有当我们仍然可以选择要发送的响应消息时,才会调用异常处理程序。 Both services provide access to an exception context containing relevant information from the point where the exception was detected, particularly the HttpRequestMessage, the HttpRequestContext, the thrown exception and the exception source. 这两种服务都提供对异常上下文的访问,该异常上下文包含检测到异常的相关信息,特别是HttpRequestMessage,HttpRequestContext,抛出的异常和异常源。

Here the sample code 这里是示例代码

public class ExceptionLogger : IExceptionLogger
{
    public virtual Task LogAsync(ExceptionLoggerContext context, 
                             CancellationToken cancellationToken)
   {


    return MyLogger.Log(context, cancellationToken);
   }   
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM