简体   繁体   中英

How do I return the TaskStatus when making a synchronous call asynchronous?

I have a old data access library that I need to use in my ASP.NET MVC application but I'm having trouble bringing it into the MVC world where many server-side operations are expected to be asynchronous. My data access library looks a like this:

public class MyOldDAL
{
    public TaskResult CreateUser(string userName)
    {
        try
        {
            // Do user creation
            return new TaskResult { Success = true, Message = "success" };
        }
        catch (Exception ex)
        {
            return new TaskResult { Success = false, Message = ex.Message };
        }
    }
}

And is called by my MVC application like this:

public class MyUserStore : IUserStore<ApplicationUser>
{
    private readonly MyOldDAL _dal = new MyOldDAL();
    public async Task CreateAsync(ApplicationUser user)
    {
        await Task.Run(() => _dal.CreateUser(user.UserName));
    }
}

This is fine until the method in Task.Run() fails for some reason. I'd like to be able to return TaskStatus.Faulted if TaskResult.Success is false but I can't find an example online on how to do it properly - all my Google searches turn up is how to use Task<T> which the IUserStore interface doesn't permit.

For the record, much as I'd like to I can't change MyOldDAL - it's targeting .NET 3.5 so no async or await there!

The normal way to report errors from tasks is via exceptions, so you'll just need to do that transformation yourself:

public class MyUserStore : IUserStore<ApplicationUser>
{
  private readonly MyOldDAL _dal = new MyOldDAL();
  public Task CreateAsync(ApplicationUser user)
  {
    var result = _dal.CreateUser(user.UserName);
    if (result.Success)
      return Task.CompletedTask;
    return Task.FromException(new InvalidOperationException(result.Message));
  }
}

Note that Task.Run should not be used on ASP.NET.

Note: As Stephen Cleary noticed in his answer, Task.Run should not be used on ASP.NET.

Original answer (before comments): Your CreateAsync method should normally be like this:

public async Task<TaskResult> CreateAsync(ApplicationUser user)
{
    return await Task.Run(() => _dal.CreateUser(user.UserName));
}

But if you can't return Task<TaskResult> from CreateAsync method... well, than you can't obtain TaskResult from CreateAsync by definition. In that case you can store result locally:

private TaskResult taskResult;

public async Task CreateAsync(ApplicationUser user)
{
    var result = await Task.Run(() => _dal.CreateUser(user.UserName));
    this.taskResult = result;
    // process taskResult wherether you need
}

Or raise event with TaskResult payload, allowing client of MyUserStore to subscribe to this event:

public event EventHandler<TaskResult> TaskCompleted;

public async Task CreateAsync(ApplicationUser user)
{
    var result = await Task.Run(() => _dal.CreateUser(user.UserName));
    this.OnTaskCompleted(result);
}

private void OnTaskCompleted(TaskResult result)
{
    this.TaskCompleted?.Invoke(this, result);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM