将异步 lambda 包装到异步方法

本文关键字:异步方法 包装 lambda 异步 | 更新日期: 2023-09-27 18:33:47

我正在尝试将我的Operations Contracts包装到 try-catch 块。问题是我的 EF 上下文在同一时间范围内被破坏。我猜问题编译器不知道该怎么做。此外,我的捕获块不处理任何异常。对不起我的英语,我希望我的代码显示我的意思:

private static async Task<T> SurroundWithTryCatch<T>(Action t, T response) where T : BaseResponse 
{
    try
    {
        await Task.Run(t);
    }
    catch (Exception e)
    {
        response.Success = false;
        response.Errors.Add(e.Message);
    }
    return response;
}
public async Task<CreateResponse> CreateAsync(CreateRequest request)
{
    var response = new CreateResponse();
    return await SurroundWithTryCatch(async delegate
    {
        var newUser = new ApplicationUser { UserName = request.UserName, Email = request.Email };
        await Database.UserManager.CreateAsync(newUser, request.Password);
        //Some another logic...
        await Database.CommitAsync();
    }, response);
}

第二行CreateAsync方法中的问题。 UserManager之前被GC清理过。所以我有ObjectDisposedException. DatabaseIUnitOfWork实现,由Autofac注入。

将异步 lambda 包装到异步方法

您正在打破await链 - t不再返回任务。由于您不再有任务,因此执行将在第一个await之后继续,而不是在整个方法完成后。将await视为return - 如果您不返回(并await/等待)任务,您将失去同步的机会。

相反,您希望传递 Func<Task> 并直接等待它:

private static async Task<T> SurroundWithTryCatch<T>(Func<Task> t, T response) where T : BaseResponse 
{
    try
    {
        await t();
    }
    catch (Exception e)
    {
        response.Success = false;
        response.Errors.Add(e.Message);
    }
    return response;
}
public async Task<CreateResponse> CreateAsync(CreateRequest request)
{
    var response = new CreateResponse();
    return await SurroundWithTryCatch(async () =>
    {
        var newUser = new ApplicationUser { UserName = request.UserName, Email = request.Email };
        await Database.UserManager.CreateAsync(newUser, request.Password);
        //Some another logic...
        await Database.CommitAsync();
    }, response);
}

Task.Run也可以工作,但您可能不希望这样做 - 您的代码是异步的,并且(猜测)您正在 ASP.NET 请求中运行,因此启动任务只是为了等待另一个任务的结果没有任何好处。 Task.Run用于在单独的线程中执行 CPU 工作,这通常是您在 ASP.NET 中避免的。