Since Silverlight enforces an a-synchronic development (you can’t call any services in sync mode), the new release of the async framework (still in CTP) brings new opportunities and simplification to Silverlight developers. As RIA services are a common way to connect Silverlight to a backend database it make sense to use the async framework to call the RIA services.
When I searched for samples of how to use the async framework with RIA I found Kyle McClelln’s blog that provides a nice solution but with couple of issues:
- If you read the code carefully you will notice that the registration for the onComplete event is executed after the function load is executed, so theoretically if the method is completed before the registration, we will miss the event and the code will never execute. of course calling the RIA Service takes time to complete but this is not good practice.
- Relatively cumbersome Bracketing required in any call to RIA function.
- Incompatible with the naming convention of the Task-based Asynchronous pattern.
So, inspired by Kyle’s blog I wrote my version of the solution to solve the above issues
using System.Collections.Generic; using System.ServiceModel.DomainServices.Client; using System.Threading.Tasks; public static class DomainContextExtension { public static Task<IEnumerable<T>> LoadAsync<T>(this DomainContext source, EntityQuery<T> query) where T : Entity { return source.LoadAsync(query, LoadBehavior.KeepCurrent); } public static Task<IEnumerable<T>> LoadAsync<T>(this DomainContext source, EntityQuery<T> query, LoadBehavior loadBehavior) where T : Entity { TaskCompletionSource<IEnumerable<T>> taskCompletionSource = new TaskCompletionSource<IEnumerable<T>>(); source.Load( query, loadBehavior, loadOperation => { if (loadOperation.HasError && !loadOperation.IsErrorHandled) { taskCompletionSource.TrySetException(loadOperation.Error); loadOperation.MarkErrorAsHandled(); } else if (loadOperation.IsCanceled) { taskCompletionSource.TrySetCanceled(); } else { taskCompletionSource.TrySetResult(loadOperation.Entities); } }, null); return taskCompletionSource.Task; } }
- Using the lambda expression in the Load function ensures that the function will complete without executing the callback.
- The function returns a Task of IEnumerable of the requested entity and copys all the information from the LoadOperation object into the Task object (cancel and errors if exist) so there is no need to deal with the LoadOperation object on the calling side,thus achieving a clean calling syntax (see the example bellow).
- The function’s name is compatible with the naming convention of Async suffix.
Example of client model function:
public Task<IEnumerable<Customer>> GetAllCustomer() { DemoDomainContext dc = new DemoDomainContext(); return dc.LoadAsync(dc.GetAllCustomerQuery()); }
And client to this function can be:
IEnumerable<Customer> result = await GetAllCustomer();
I find that the above is a avery practical and clean solution to using the new and amazing Async framework combined with RIA.
Update – I updated the code for Visual Studio 2010 SP1 + Silverlight 5 and added the functions:
- LoadEntityAsync – Supports methods that returns a single Entity and not IEnumerable<Entity>
- InvokeAsync – Support for RIA Invoke methods, so you can write code like:
string methodResult = await dc.InvokeAsync(() =&gt; dc.InvokeMethodName(parameter1));
Update – Update version for Visual Studio 2012 + Silverlight 5.
Source Code for this article
Source Code for this article – VS2012
[…] CTP) to load the query. For more detail on using Async framework with RIA service please refer to this […]
[…] The class SilverlightOccasionallyConnected.OfflineHelper has a static Boolean property IsApplicationOnline. The property is initiated with the built-in NetworkInterface.GetIsNetworkAvailable() value. The idea is to set the status at the application loading and to enable control of this property to the application. If the application is online, the method use the Async framework to load the query from the server as I described in detail in this article. […]
For issue 1, RIA does a little extra work to ensure the event pattern is always safe, even in multi-threaded scenarios.
HI,
I can’t compile your source project.
Error 3 The type or namespace name ‘async’ could not be found (are you missing a using directive or an assembly reference?) C:\Users\perpaulo\Documents\Visual Studio 2010\Projects\AsyncRia\Demo\Demo\DemoViewModel.cs 52 17 Demo
Error 4 The name ‘await’ does not exist in the current context C:\Users\perpaulo\Documents\Visual Studio 2010\Projects\AsyncRia\Demo\Demo\DemoViewModel.cs 55 30 Demo
The async for silverlight is included, right ? Any dependency ?
Thanks in advance!!!!!!
Paulo
Hi Paulo,
The asynchronous framework includes changes to the c# compiler, so you should download and install the Microsoft Visual Studio Asynchronous Framework before you will be able to compile the project.
The asynchronous framework can be download from here: http://msdn.microsoft.com/en-gb/vstudio/async.aspx
Nice, works great, thanks!
Richard Hiya, I am really glad I have found this info. Nowadays bloggers publish only about gossips and net and this is really irritating. A good blog with exciting content, that is what I need. Thank you for keeping this web site, I’ll be visiting …
Hello There. I discovered your weblog the use of msn. That is an extremely well written article. I’ll make sure to bookmark it and come back to read extra of your helpful information. Thanks for the post. I’ll certainly return….
” if the method is completed before the registration, we will miss the event and the code will never execute. of course calling the RIA Service takes time to complete but this is not good practice”
Hi this is not correct. On THW First Look you are right but if you Take a deeper Look to the loadoperation class you will See that it Works Ester the call is Finishs befördert you connect the compleated event
As kyle mention before, it safe, but it’s not obvious from looking at the code.
Hello Oren,
This example is what I feel will be useful in my scenario. The issue is I am not able to create a VB version of your extension class.
Could you or someone help please.
Thanks
Supreet
Hi Supreet,
Please check the vb version here
Regards,
Oren.
[…] I am using the Async framework (still in CTP) to load the query. For more detail on using Async framework with RIA service please refer to this article. […]
How would you use this with a simple DomainService Method like this:
namespace HelloWorldTest.Web.Services
{
[EnableClientAccess()]
public class HelloWordService : DomainService
{
public string HelloWorld(string s)
{
return “Hello World: ” + s;
}
}
}
Invoke methods are trickier as the auto-generate code for them is not so flexible.
I updated the source code to include the InvokeAsync method so you can call the HelloeWorld like this:
string s = await dc.InvokeAsync(() => dc.HelloWorld(s));
Hello, I’m interested in the function that you implement InvokeAsync but when I use it I get an error: “The ‘await’ operator can only be used within an async method. Consider marking this method with the ‘async’ modifier and changing its return type to ‘Task’.”
I’m under VS 2012 SL5 ans i use the Async Targeting Pack for Visual Studio
I updated the source for Visual Studio 2012 + SL5.
Make sure you are adding the “async” keyword to the method’s signature.
Great, Thank You, i try by myself without result 🙂
Whats up! I simply want to give an enormous thumbs up for the
nice information you’ve got right here on this post.
I will probably be coming back to your weblog for more soon.