New Posts New Posts RSS Feed: Rich compiler support for the task-based asynchronous pattern.
  FAQ FAQ  Forum Search   Calendar   Register Register  Login Login

Rich compiler support for the task-based asynchronous pattern.

 Post Reply Post Reply
Author
johnl View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 24-Jan-2011
Posts: 35
Post Options Post Options   Quote johnl Quote  Post ReplyReply Direct Link To This Post Topic: Rich compiler support for the task-based asynchronous pattern.
    Posted: 09-Oct-2012 at 2:22pm

We received a great question via email today and I wanted to share it (and the answer!) with you:


In the previous version of Devforce and MVVM, the ViewModel class called the repository something like this

private void FetchMembers()
{
this.IsBusy = true;
Repository.GetMembers(
(members) => // query success
{
this.IsBusy = false;
ResetMembersList(members);
},
(error) => // failed
{
this.IsBusy = false;
DisplayMessage(error.Message);
});
}
private void ResetMembersList(IEnumerable<Member> members)
{
Members.Clear();
members.ForEach(Members.Add);
}

Now using Async and Devforce 2012, my GetMembersAsync returns a Task<IEnumerable<Member>>. It doesn’t seem right that the ViewModel receives a Task and has to decipher the result and pull it apart to get the result. It would seem more logical to have a Task service. In my Task service I have a GetMembers method that calls the GetMembersAsync method of the Repository. The ViewModel calls this method now and no longer calls the Repository. The GetMembers method gets back a Task. It is responsible for determining the outline of the call, unbundling the result and send back an IEnumerable collection back to the ViewModel. Now the ViewModel does not have to know about Tasks. It puts a layer between the ViewModel and Repository.

What do you think about this idea? Is there a better way to do this?

Yes, what you are describing as a service is all handled by the compiler. Rich compiler support for the Task-based Asynchronous Pattern does it all for you. You rarely touch the actual Task. So, let’s look at how this would look with the example below. As you said GetMemberAsync returns Task<IEnumerable<Member>>, so the FetchMembers method done properly looks like this. The async keyword tells the compiler that it needs to apply the magic sauce.

private async void FetchMembers()
{
try
{
this.IsBusy = true;
ResetMembersList(await Repository.GetMembersAsync());
}
catch (Exception error)
{
DisplayMessage(error.Message);
}
finally
{
this.IsBusy = false;
}
}
private void ResetMembersList(IEnumerable<Member> members)
{
Members.Clear();
members.ForEach(Members.Add);
}

Notice, you never need to “decipher” the Task. If GetMemberAsync succeeds, the await keyword extracts the result and passes it to ResetMembersList. If GetMemberAsync fails, await throws an exception, which you can simply handle with the try catch and you can take care of the busy state in the finally. One of the great things about the Task-based Asynchronous Pattern is that you write the code as if it was synchronous, except you put await in front of asynchronous methods.

private async Task FetchMembers()
{
try
{
this.IsBusy = true;
ResetMembersList(await Repository.GetMembersAsync());
}
catch (Exception error)
{
DisplayMessage(error.Message);
}
finally
{
this.IsBusy = false;
}
}
private void ResetMembersList(IEnumerable<Member> members)
{
Members.Clear();
members.ForEach(Members.Add);
}

If you also want to return a result value, you can do that to. Let’s say you want FetchMembers to return the list of members. In that case it would look like this.

private async Task<IEnumerable<Member>> FetchMembers()
{
try
{
this.IsBusy = true;
var members = await Repository.GetMembersAsync();
ResetMembersList(members);
return members;
}
catch (Exception error)
{
DisplayMessage(error.Message);
throw error; // Fail Task
}
finally
{
this.IsBusy = false;
}
}
private void ResetMembersList(IEnumerable<Member> members)
{
Members.Clear();
members.ForEach(Members.Add);
}

Again, notice you don’t actually return Task<IEnumberable<Member>>, you just return IEnumerable<Member> and the compiler packages that up in the returned Task. In case of an error, just re-throw the exception and the compiler will then fault the Task, so that the caller knows not to try to extract the result value.

Back to Top
 Post Reply Post Reply

Forum Jump Forum Permissions View Drop Down