Wahlin on .NET
Simplify Calling a WCF Service from Silverlight
Large-scale Silverlight applications can end up making hundreds of calls from the application to WCF service operations. When I first started building Silverlight applications, I called WCF services using the standard technique, which is to define a client-side class that's used to call the WCF service using the generated service proxy. The service agent class handles instantiating the WCF proxy object and calling the appropriate operations. Listing 1 shows a few examples. Each of the methods accepts the parameters passed to the WCF service as well as a callback method that's called when the service returns data.
public void GetJobs(EventHandler callback)
{
IJobPlanService proxy = GetProxy();
proxy.GetJobsCompleted += callback;
proxy.GetJobsAsync();
}
public void GetEmployees(EventHandler
callback)
{
IJobPlanService proxy = GetProxy();
proxy.GetEmployeesCompleted += callback;
proxy.GetEmployeesAsync();
}
public void GetEmployeesByJobID(int jobID,
EventHandler callback)
{
IJobPlanService proxy = GetProxy();
proxy.GetEmployeesByJobIDCompleted += callback;
proxy.GetEmployeesByJobIDAsync(jobID);
}
public void GetTimeSheetViews(int? jobID, int? empID, string weekEnding,
EventHandler callback)
{
IJobPlanService proxy = GetProxy();
proxy.GetTimeSheetViewsCompleted += callback;
proxy.GetTimeSheetViewsAsync(jobID, empID, weekEnding);
}
Listing 1.
Calling WCF service operations using a client proxy object.
After writing nearly the same code method after method (aside from changes in the event name and method name), I opted for a simplified approach that provides a way to make WCF service operation calls using a single method. That way I don't have to continually write wrapper methods just to call a service operation, which can get tedious. Some people will like the following code since it can eliminate a ton of code from your Silverlight project (the code would work fine outside of Silverlight too, by the way). Others won't like it since reflection is involved. I personally don't find that reflection is a problem in this scenario, since it's running on the client-side.
Here's how it works:
1. The CallService method shown in Listing 2 accepts an async callback delegate as well as the parameter data that should be passed to the service. In other words, tell it what method to call once the service returns data as well as what data to pass up to the service operation.
2. When calling the CallService method you must supply the type of EventArgs that will be returned from the service call. This is done using generics.
///
/// Used to call a WCF service operation.
///
/// The type of EventArgs that will be returned
/// by the service operation.
/// The method to call once the WCF call
/// returns (the callback).
/// Any parameters that the service
/// operation expects.
public void CallService(EventHandler callback,
params object[] parameters) where T : EventArgs
{
string action = typeof(T).Name.Replace("CompletedEventArgs",
String.Empty);
IJobPlanService proxy = new JobPlanServiceClient();
Type t = typeof(JobPlanServiceClient);
t.GetEvent(action + "Completed").AddEventHandler(proxy, callback);
t.InvokeMember(action + "Async", BindingFlags.InvokeMethod, null,
proxy, parameters);
}
Listing 2. Creating a re-useable method capable of calling any WCF service operation.
An example of using the CallService method is shown next:
ServiceAgent _Proxy = new ServiceAgent();
public void GetAreasByJobID()
{
_Proxy.CallService((s,e) =>
this.CurrentTimeSheetView.Areas = e.Result,
this.TimeSheetJob.JobID);
}
The GetAreasByJobID method passes a type of GetAreasByJobIDCompletedEventArgs as the generic type to CallService, defines the async callback using a lambda expression (although a separate method could certainly be defined) and passes the parameter that the service operation expects. Multiple parameters can be passed when needed. CallService knows which WCF service operation to call based upon the generic type that's passed, since WCF service proxy object's always create EventArgs classes that end with "CompletedEventArgs".
The CallService‹T› method simply removes the string "CompletedEventArgs" to get the operation name, instantiates the service proxy object and then uses reflection to wire up the appropriate event and async method to call. If you use several different service proxy objects you could certainly handle that as well with generics. I played around with ChannelFactory as well but opted for this approach mainly because it was more straightforward in my opinion, and because I wanted to use the generated WCF proxy anyway.
If scalability was an issue (which is not the case here since this runs on the client-side), then I'd go with the standard approach of using the WCF proxy methods that are generated as shown in the first section of code above. For an application my company is currently working on, this approach to calling WCF service operation has eliminated hundreds of lines of redundant code (which will grow to thousands of lines of eliminated code based on the scope of the project). That means we have less to worry about. The other major benefit is this approach eliminates the time it would have taken to write the wrapper methods.
About the Author
Dan Wahlin (Microsoft MVP for ASP.NET and XML Web Services) is the founder of The Wahlin Group which specializes in .NET and SharePoint onsite, online and video training and consulting solutions. Dan also founded the XML for ASP.NET Developers Web site, which focuses on using ASP.NET, XML, AJAX, Silverlight and Web Services in Microsoft's .NET platform. He's also on the INETA Speaker's Bureau and speaks at conferences and user groups around the world. Dan has written several books on .NET including "Professional Silverlight 2 for ASP.NET Developers," "Professional ASP.NET 3.5 AJAX, ASP.NET 2.0 MVP Hacks and Tips," and "XML for ASP.NET Developers." Read Dan's blog here.