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.

Reader Comments:

Wed, Jan 13, 2010 montasir Bangladesh, Dhaka

i just want fill up a datagrid using '=>' this symbol, as you did here _Proxy.CallService((s,e) => this.CurrentTimeSheetView.Areas = e.Result, this.TimeSheetJob.JobID);

Wed, Jan 13, 2010 montasir Banagladesh

It is very interesting. I have tried to implement. there were error could give me the full class file source code.

Sat, Jan 2, 2010 Mike http://jerseydude.wordpress.com/

Two limitations: If your service method does not return a value (void), there will not be an EventHandler type to use in the CallService. Also, if you muck up the parameter list you obviously do not get a compiler error -- instead it is a run-time error on the Invoke call.

Wed, Dec 30, 2009 Mike http://jerseydude.wordpress.com/

This is a fine article Dan. We are going to switch to this method going forward. Note to other readers, use View Source in the browser to get the correct source code. Also, the two lower case t's in the CallService declaration should be uppercase T's.

Tue, Dec 15, 2009 James Wilson

That should have said: ... CallService<T>(EventHandler<T>... the less-than and greater-than symbols are being treated as html. I wonder if that's what happened in the original post.

Tue, Dec 15, 2009 James Wilson

The CallService signature should look like this: ... CallService(EventHandler... Excellent article though, I will definitely put this to use. Thank you for sharing it!

Add Your Comments Now:

Your Name:(optional)
Your Email:(optional)
Your Location:(optional)
Comment:
Please type the letters/numbers you see above