In Silverlight 4, all WCF calls made from the UI thread must be asynchronous. This is fine. The WCF client code exposes methods and events like
void GetDataAsync(SomeArgument a);
event EventHandler<GetDataCompletedEventArgs> GetDataCompleted;
Is it possible to wrap it or configure WCF/Silverlight to generate the following?
void GetDataAsync(SomeArgument a, EventHandler<GetDataCompletedEventArgs>);
In my project I created a class responsible for all method calls, that is accessable to higher layers (like view model). It exposes methods like:
void GetData(SomeArgument a, Action<SomeResult> callback);
Now the serviceClient is reusable, so I need to unsubscribe from the *Completed event after the call is finished. My best approach so far is this:
EventHandler<T> MakeHandler<T>(Action<T> callback) where T : AsyncCompletedEventArgs
{
return (sender, eventArgs) =>
{
callback(eventArgs); // perform some operations in view model
((Action)eventArgs.UserState)(); // this is to unsubscribe from event
};
}
void GetData(SomeArgument a, Action<SomeResult> callback)
{
var handler = MakeHandler<GetDataCompletedEventArgs>((s, ea) => callback(ea.Result));
serviceClient.GetDataCompleted += handler
serviceClient.GetDataAsync(a, new Action(() => serviceClient.GetDataCompleted -= handler));
}
I’d really like to avoid having to retype the whole GetData() wiring for every used WCF method and just do something like:
void GetData(SomeArgument a, Action<SomeResult> callback)
{
serviceClient.GetDataAsync(a, callback);
}
You can access the Begin/End “.NET Async Pattern” for your WCF service by using the Service interface of the ServiceClient. For example if you have a WCF service called “Service1” your Silverlight project will contain a “Service1Client” class (that uses the Async/Event pattern to expose operations) but it also explicitly implements an interface called “Service1” which uses the Begin/End pair for each operation. Use:-
Now with access to the Begin/End pair things get a little easier. You can use the following Generic function to create the basic plumbing to calling the Async pattern:
You can consume it with a specific function: