.net core 项目,使用async await 中间件无法捕获异常的问题

起因

项目中使用了异常中间件捕获,但是在一个接口请求中手动抛出的异常无法被捕获,程序直接关闭了

业务解释

在一个登录功能中,有短信验证码登录和密码登录,两个方法类似,只有验证逻辑有差别。
所以对两个方法进行了封装,该封装需要传入一个委托Action,无返回值。
两个接口只需要调用该方法并传入不同的验证逻辑即可,如果验证不通过在验证逻辑中手动抛异常由异常中间件统一捕获。

发现问题

在调用密码登录接口时,因为只需要验证密码,不需要调用其他组件,所以没有使用async/await,异常是可以被正常捕获的
在调用短信验证码登录接口时,需要调用验证码组件进行验证,使用了async/await,异常无法被捕获

代码示例

//封装代码
 async Task<ApiResult> LoginAsync(Users users, Action<Users, Users> action)
 {
     //一些逻辑
     action.Invoke(users, entity);
     //一些逻辑
     return ApiResult<object>.OK();
 }
//密码登录
  public async Task<ApiResult> LoginByPwdAsync(Users users)
 {
     return await LoginAsync(users, (args, entity) =>
     {
          throw new KnowException(ApiResult.ClientError("密码错误~"));
     });
 }
 //验证码登录
public async Task<ApiResult> LoginBySmsCodeAsync(string sms_code, Users users)
{
    return await LoginAsync(users, async (args, entity) =>
    {
          throw new KnowException(ApiResult.ClientError("验证码错误~"));//该异常无法被捕获
    });
}

原因

原因很简单, Action 是不支持异步调用的, Action 委托表示一个不返回值的方法。由于 Action 本身是同步的,它不能直接处理异步操作。当你在一个 Action 委托中使用 async 和 await 关键字时,编译器会生成一个返回 Task 的方法,而这与 Action 的签名不匹配。
换成 Func 即可,如果没有返回值,则使用 Func<Task>

更改后的代码


//封装代码
 async Task<ApiResult> LoginAsync(Users users, Func<Users, Users, Task> action)//Action 改成 Func,并返回Task,这个很重要
 {
     //一些逻辑
     action.Invoke(users, entity);
     //一些逻辑
     return ApiResult<object>.OK();
 }
//密码登录
  public async Task<ApiResult> LoginByPwdAsync(Users users)
 {
     return await LoginAsync(users,async (args, entity) =>
     {
          throw new KnowException(ApiResult.ClientError("密码错误~"));
          await Task.CompletedTask;
     });
 }
 //验证码登录
public async Task<ApiResult> LoginBySmsCodeAsync(string sms_code, Users users)
{
    return await LoginAsync(users, async (args, entity) =>
    {
          throw new KnowException(ApiResult.ClientError("验证码错误~"));//该异常无法被捕获
          //此处需要调用验证码组件,所以使用了async
          await Task.CompletedTask;
    });
}
posted @ 2024-07-11 16:37  袈裟和尚  阅读(6)  评论(0编辑  收藏  举报