Home Ask Login Register

Developers Planet

Your answer is one click away!

user3818229 February 2016

Wrap async lambda to the async method

I'm trying to wrap my Operations Contracts to the try-catch block. The problem is that my EF context destroyed in the same time scope. I guess the problem compiler doesn't know what to do properly. Also my catch block doesn't handle any exceptions. Sorry for my English, I hope my code show what I mean:

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

The problem in the second line of CreateAsync method. UserManager was cleaned by GC earlier. So I have ObjectDisposedException. Database is the IUnitOfWork implementation and injected by Autofac.

Answers


Luaan February 2016

You're breaking the await chain - t no longer returns a task. Since you no longer have a task, the execution will continue after the first await, rather than after the whole method is done. Think of await as return - if you don't return (and await/wait for) a Task, you lose your chance at synchronization.

Instead, you want to pass Func<Task>, and await it directly:

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 also works, but you probably don't want that anyway - your code is asynchronous, and (a guess) you're running in a ASP.NET request, so there's no benefit to launching a task just to wait on the result of another task. Task.Run is used for doing CPU work in a separate thread, something you usually want to avoid in ASP.NET.

Post Status

Asked in February 2016
Viewed 2,401 times
Voted 4
Answered 1 times

Search




Leave an answer


Quote of the day: live life