【问题标题】:ExceptionFilterAttribute not triggered when using Task.Factory.StartNew使用 Task.Factory.StartNew 时未触发 ExceptionFilterAttribute
【发布时间】:2017-09-06 14:24:41
【问题描述】:

我正在开发一个 ASP.NET Web API,在我的一个控制器操作中我使用了一个 Task.Factory.StartNew 调用。

但是,当任务内部抛出异常时,这不会触发我配置的异常过滤器。

Controller.cs

public class MyController : ApiController
{
    [HttpPost]
    public HttpResponseMessage Post()
    {
        Task.Factory
            .StartNew(() => DoTheThing())
            .ContinueWith(tsk => { throw new Exception("Webhook Exception", tsk.Exception); }, TaskContinuationOptions.OnlyOnFaulted);

        return new HttpResponseMessage(HttpStatusCode.OK);
    }
}

ExceptionFilter.cs

public class ExceptionFilter : ExceptionFilterAttribute
{
    public override void OnException(HttpActionExecutedContext context)
    {
        throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.InternalServerError)
        {
            Content = new ObjectContent(typeof(object), new
            {
                Message = "Critical Error",
                ExceptionMessage = "An error occurred, please try again or contact the administrator.",
                Type = ExceptionType.Unhandled
            }, new JsonMediaTypeFormatter()),
            ReasonPhrase = "Critical Error"
        });
    }
}

Global.asax.cs

public class MyApplication : HttpApplication
{
    protected void Application_Start()
    {            
        GlobalConfiguration.Configuration.Filters.Add(new ExceptionFilter());
    }
}

我可以调试并触发 ContinueWith 方法并抛出新的异常。但是过滤器没有被触发。

【问题讨论】:

  • 您没有观察(重新)抛出的Exception,因此它是Unobserved Exceptions。见:Task Exception Handling in .NET 4.5
  • 感谢您的链接,我想我现在明白了这个问题。我正在尝试做不可能的事情,因为过滤器只会在我的操作中捕获异常。但我希望我的操作在我的任务结束前立即返回。

标签: c# asp.net asp.net-web-api


【解决方案1】:

过滤器没有被触发,因为异常是在与控制器动作方法线程不同的线程中抛出的。你可以:

  1. 等待任务

    [HttpPost]
    public async Task<HttpResponseMessage> Post()
    {
        await Task.Factory
            .StartNew(() => DoTheThing())
            .ContinueWith(tsk => { throw new Exception("Webhook Exception", tsk.Exception); }, TaskContinuationOptions.OnlyOnFaulted);
    
        return new HttpResponseMessage(HttpStatusCode.OK);
    }
    
  2. 等待任务

    [HttpPost]
    public HttpResponseMessage Post()
    {
        var task = Task.Factory
                       .StartNew(() => DoTheThing())
                       .ContinueWith(tsk => { throw new Exception("Webhook Exception", tsk.Exception); }, TaskContinuationOptions.OnlyOnFaulted);
    
        task.Wait();
    
        return new HttpResponseMessage(HttpStatusCode.OK);
    }
    

所有这些方法都在 action 方法中重新抛出异常,并且过滤器会捕获它。

【讨论】:

  • 标记为正确,因为它回答了我的问题。这不是我想要的解决方案,因为我打算立即从我的操作中返回,而不是等待任务完成。但我现在明白这与过滤器的设计相冲突,过滤器只在控制器操作线程中捕获异常。
  • 实际上异常过滤器捕获所有异常,但Task在自己的线程中“处理”它们。无论如何,您立即从操作方法返回“HttpStatusCode.OK”,但随后您从过滤器返回另一个状态-“InternalServerError”。但是,请求已经被处理并且客户端已经得到响应。您可以在操作返回后在继续任务中记录异常,但不能重写响应状态。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-11-19
  • 1970-01-01
  • 2020-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-15
相关资源
最近更新 更多