Asynchronous 在异步/等待任务操作中未捕获异常

Asynchronous 在异步/等待任务操作中未捕获异常,asynchronous,exception-handling,asp.net-core,async-await,task,Asynchronous,Exception Handling,Asp.net Core,Async Await,Task,我正在用.NETCore编写一个ASP.NETMVC站点。我试图封装一些常见的异常处理。在基类中,我有这个方法 public abstract class BaseController<TController> : Controller where TController : Controller { protected IActionResult ExceptionHandledOperation(Func<IActionResult> operation, F

我正在用.NETCore编写一个ASP.NETMVC站点。我试图封装一些常见的异常处理。在基类中,我有这个方法

public abstract class BaseController<TController> : Controller where TController : Controller
{
    protected IActionResult ExceptionHandledOperation(Func<IActionResult> operation, Func<IActionResult> handleException)
    {
        try
        {
            return operation.Invoke();
        }
        catch (Exception exception)
        {
            Logger.LogError($"Operation {Request.Path} Exception", exception);

            return handleException.Invoke();
        }
    }
}
公共抽象类BaseController:Controller,其中TController:Controller
{
受保护的IActionResult异常HandledOperation(Func operation,Func handleException)
{
尝试
{
返回操作。Invoke();
}
捕获(异常)
{
Logger.LogError($“操作{Request.Path}异常”,异常);
返回handleException.Invoke();
}
}
}
从继承自该基类的控制器中,我使用如下方法:

[Route("api/[controller]")]
public class MyController : BaseController<MyController>
{
    [HttpGet]
    public IActionResult Get()
    {
        return ExceptionHandledOperation(() => Ok(_someService.GetAsync().Result),
                                         NotFound);
    }
}
[路由(“api/[控制器]”)]
公共类MyController:BaseController
{
[HttpGet]
public IActionResult Get()
{
返回ExceptionHandledOperation(()=>Ok(_someService.GetAsync().Result),
未发现);
}
}
假设_someService.GetAsync()方法是:

public class SomeService
{
    public async Task<PreconfigurationData> GetAsync()
    {
        // http request removed for brevity

        if (!response.IsSuccessStatusCode)
            throw new Exception("SomeService Exception");
    }
}
公共类服务
{
公共异步任务GetAsync()
{
//为简洁起见,删除了http请求
如果(!response.issucessStatusCode)
抛出新异常(“SomeService异常”);
}
}
这工作正常,可以在基类方法中捕获我的异常并返回NotFound结果

但是,我希望避免从SomeService.GetAsync方法调用.Result。我读到的每一篇文章都说不要这样做,因为这样会导致僵局

因此,我将我的基本控制器修改为:

public abstract class BaseController<TController> : Controller where TController : Controller
{
    protected async Task<IActionResult> ExceptionHandledOperationAsync(Func<IActionResult> operation, Func<IActionResult> handleException)
    {
        try
        {
            return await Task.Run(() => operation.Invoke());
        }
        catch (Exception exception)
        {
            Logger.LogError($"Operation {Request.Path} Exception", exception);

            return await Task.Run(() => handleException.Invoke());
        }
    }
}
公共抽象类BaseController:Controller,其中TController:Controller
{
受保护的异步任务异常HandleOperationAsync(Func操作,Func handleException)
{
尝试
{
返回wait Task.Run(()=>operation.Invoke());
}
捕获(异常)
{
Logger.LogError($“操作{Request.Path}异常”,异常);
返回wait Task.Run(()=>handleException.Invoke());
}
}
}
我的控制器是这样的:

[Route("api/[controller]")]
public class MyController : BaseController<MyController>
{
    [HttpGet]
    public async Task<IActionResult> Get()
    {
        return await ExceptionHandledOperationAsync(() => Ok(_someService.GetAsync()),
                                                    NotFound);
    }
}
[Route("api/[controller]")]
public class MyController : BaseController<MyController>
{
    [HttpGet]
    public async Task<IActionResult> Get()
    {
        return await ExceptionHandledOperationAsync(async () => Ok(await _someService.GetAsync()),
                                                    NotFound);
    }
}
[路由(“api/[控制器]”)]
公共类MyController:BaseController
{
[HttpGet]
公共异步任务Get()
{
return await exception handledOperationAsync(()=>Ok(_someService.GetAsync()),
未发现);
}
}
但是,从SomeService.GetAsync方法引发的异常从未被捕获,并且在处理该异常时,我从未获得打算发送的NotFound响应

我读到的每一篇文章都说,你只需要在try中等待任务,然后任何异常都会被捕获,但我的却从来没有


已解决


我终于解决了这个问题。感谢Tseng的帮助。

我同意上面关于不在ASP.NET应用程序中使用Task.Run的评论。也就是说,您可以尝试在Invoke方法周围放置try/catch

例如:

 try
 {
     return await Task.Run(() =>
     {
         try
         {
              operation.Invoke();
         }
         catch (Exception ex)
         {
              // log exception
         }
     });
  }
  catch (Exception ex)
  {
      // captured SynchronizationContext
  }

我终于明白了曾荫权对我说的话之后,我才能够让这项工作顺利进行。我就是这样改变的:

public abstract class BaseController<TController> : Controller where TController : Controller
{
    protected async Task<IActionResult> ExceptionHandledOperationAsync(Func<Task<IActionResult>> operation, Func<IActionResult> handleException)
    {
        try
        {
            return await operation.Invoke();
        }
        catch (Exception exception)
        {
            Logger.LogError($"Operation {Request.Path} Exception", exception);

            return handleException.Invoke();
        }
    }
}
公共抽象类BaseController:Controller,其中TController:Controller
{
受保护的异步任务异常HandleOperationAsync(Func操作,Func handleException)
{
尝试
{
return wait operation.Invoke();
}
捕获(异常)
{
Logger.LogError($“操作{Request.Path}异常”,异常);
返回handleException.Invoke();
}
}
}
我的控制器是这样的:

[Route("api/[controller]")]
public class MyController : BaseController<MyController>
{
    [HttpGet]
    public async Task<IActionResult> Get()
    {
        return await ExceptionHandledOperationAsync(() => Ok(_someService.GetAsync()),
                                                    NotFound);
    }
}
[Route("api/[controller]")]
public class MyController : BaseController<MyController>
{
    [HttpGet]
    public async Task<IActionResult> Get()
    {
        return await ExceptionHandledOperationAsync(async () => Ok(await _someService.GetAsync()),
                                                    NotFound);
    }
}
[路由(“api/[控制器]”)]
公共类MyController:BaseController
{
[HttpGet]
公共异步任务Get()
{
返回Wait ExceptionHandledOperationAsync(async()=>Ok(wait\u someService.GetAsync()),
未发现);
}
}

您的代码中存在逻辑错误。调用
return wait Task.Run(()=>handleException.Invoke())但在函数委托内部,您可以运行异步代码而不等待它(此处:
等待异常处理操作同步(()=>Ok(\u someService.GetAsync()),NotFound)

因此,在try/catch块中,在异步调用完成之前,该方法被执行并立即返回

正如我的建议中指出的,您的函数委托也需要等待,请阅读:returns
Task

public abstract class BaseController<TController> : Controller where TController : Controller
{
    protected async Task<IActionResult> ExceptionHandledOperationAsync<T>(
        Func<Task<T>> operation,
        Func<object, IActionResult> successHandler,
        Func<IActionResult> exceptionHandler
    )
    {
        try
        {
            return successHandler.Invoke(await operation.Invoke());
        }
        catch (Exception exception)
        {
            //Logger.LogError($"Operation {Request.Path} Exception", exception);

            return exceptionHandler.Invoke();
        }
    }
}

[Route("api/[controller]")]
public class MyController : BaseController<MyController>
{
    [HttpGet]
    public async Task<IActionResult> Get()
    {
        return await ExceptionHandledOperationAsync(() => _someService.GetAsync(), Ok, NotFound);
    }
}
公共抽象类BaseController:Controller,其中TController:Controller
{
受保护的异步任务异常HandledOperationAsync(
Func操作,
Func successHandler,
Func异常处理程序
)
{
尝试
{
返回successHandler.Invoke(wait operation.Invoke());
}
捕获(异常)
{
//Logger.LogError($“操作{Request.Path}异常”,异常);
返回exceptionHandler.Invoke();
}
}
}
[路由(“api/[控制器]”)]
公共类MyController:BaseController
{
[HttpGet]
公共异步任务Get()
{
return wait exception handledOperationAsync(()=>\u someService.GetAsync(),Ok,NotFound);
}
}
您需要将
成功处理程序
(将结果传递给
确定
)移动到如上所示的方法中。但这确实是一个难看的代码。
SomeService
应该如何处理服务故障本身,并在找不到任何值时返回
null


返回
NotFound()
on exception似乎很奇怪,因为它表明该记录不存在,但可能由于网络连接或数据序列化而失败。

不要调用
Task。在ASP.NET核心应用程序中运行
。您不会从中获得任何好处,甚至可能会降低性能,并且可能会弄乱线程池m管理