当前位置: 首页 > 知识库问答 >
问题:

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

江英卓
2023-03-14

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

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();
        }
    }
}

从继承自该基类的控制器中,我使用如下方法:

[Route("api/[controller]")]
public class MyController : BaseController<MyController>
{
    [HttpGet]
    public IActionResult Get()
    {
        return ExceptionHandledOperation(() => Ok(_someService.GetAsync().Result),
                                         NotFound);
    }
}

假设_someservice.getAsync()方法如下:

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

        if (!response.IsSuccessStatusCode)
            throw new Exception("SomeService Exception");
    }
}

这工作得很好,将捕获基类方法中的异常并返回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());
        }
    }
}
[Route("api/[controller]")]
public class MyController : BaseController<MyController>
{
    [HttpGet]
    public async Task<IActionResult> Get()
    {
        return await ExceptionHandledOperationAsync(() => Ok(_someService.GetAsync()),
                                                    NotFound);
    }
}

但是,从SomeService.getAsync方法引发的异常从未被捕获,而且在处理异常时,我从未获得打算发送的NotFound响应。

我读到的每一个地方都说你只需要在尝试中等待任务,然后任何异常都会被发现,但我的从来没有。

已解决

共有1个答案

季博
2023-03-14

您的代码中有一个逻辑错误。您调用return await task.run(()=>handleexception.invoke());但是在函数委托中,您运行异步代码而不等待它(这里:await ExceptionHandledOperationAsync(()=>Ok(_someservice.getasync()),NotFound)

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

正如我的建议中所指出的,函数委托也需要是可等待的,请阅读:returnstask

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);
    }
}

您还需要将successshandler(将结果传递给OK)移动到该方法中,如上图所示。但它真的是丑陋的代码。因此,SomeService应该自己处理服务故障,并在未找到任何值时返回null

异常时返回notfound()似乎非常奇怪,因为它表明记录不存在,但可能由于网络连接或数据序列化而失败。

 类似资料:
  • 我正在与async Wait try catch块斗争几天。 这个异步函数中的try-catch是否正确? 这就是我创建自定义错误类并全局导出的方式。 要求: 故意换了工作。我想找份工作。国际直拨电话 这样我就能抓住错误。如果有错误,则抛出新创建的自定义错误类。但抛出队列错误将导致日志记录 同样,即使不需要捕捉那个里的错误,因为try块在工作,若我抛出QueueError,我只想捕捉最后一个cat

  • 问题内容: 我想同时下载一些文件,例如100个文件。因此,我决定将下载线程添加到调度队列中,GCD会调整同时运行多少个线程。 这里的问题是:中的块将立即完成,因为它将在另一个线程上运行。因此,如果长度为100,它将立即创建100个线程。 如何配置块以等待下载任务完成?我不想使用,因为它只允许同时运行一个下载任务。 问题答案: 要扩展Abhinav的答案,您应该: 使用创建一个组。 在开始每个下载任

  • 问题内容: 我不确定如何处理这种情况,因为我是iOS开发和Swift的新手。我正在像这样执行数据获取: 我的loadShows()函数解析从加载到UIWebView的网站中获取的大量数据。问题是我在loadShows函数中有一个等待10秒钟左右的计时器。这允许页面中的javascript在开始解析数据之前完全加载。我的问题是完成处理程序在我的loadShows()之前完成。 我想做的是为“ isC

  • 问题内容: 我正在研究节点7异步/等待功能,并不断跨这样的代码绊脚 这似乎是使用异步/等待解决/拒绝或返回/抛出的唯一可能性,但是,v8不会在try / catch块中优化代码吗? 有其他选择吗? 问题答案: 备择方案 替代方法: 显式地使用诺言将是这样的: 或类似的东西,使用延续传递样式: 原始例子 您的原始代码所做的是暂停执行并等待由其返回的诺言解决。然后,它继续执行,并将返回的值写入,如果承

  • 我试图在react/electron项目中使用async/await,但它不起作用。我想要的是获取docker容器状态列表。但是安慰。日志(列表)返回未定义的。 有人能帮我吗?:)

  • 我只想确保我很好地理解异步await和task.run或task.whenall之间的区别 所以异步等待就是处理异步方法。它意味着隐含着一个处理顺序。 我在不阻塞主线程的情况下运行了一个很长的处理,并等待结果继续。 对于task.run和task.when,这里有一个多线程的新概念。这意味着我可以在一个新线程上启动一个长进程,它不会等待完成来继续代码。代码在新线程上。在这个线程上,我可以等待方法。