Simplifying the Process of Calling a WCF Service from Silverlight (or any .NET Application)
I’m currently working on a large Silverlight 3 project for a client that will ultimately have hundreds of calls from Silverlight to WCF service operations. Initially I did things the standard way which is to define a client-side class that’s used to call the WCF service using the generated service proxy (I’m basically following a service agent type of pattern). The service agent class handles instantiating the WCF proxy object and calling the appropriate operations. Here are a few examples….each of these methods accept 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<GetJobsCompletedEventArgs> callback) { IJobPlanService proxy = GetProxy(); proxy.GetJobsCompleted += callback; proxy.GetJobsAsync(); } public void GetEmployees(EventHandler<GetEmployeesCompletedEventArgs> callback) { IJobPlanService proxy = GetProxy(); proxy.GetEmployeesCompleted += callback; proxy.GetEmployeesAsync(); } public void GetEmployeesByJobID(int jobID, EventHandler<GetEmployeesByJobIDCompletedEventArgs> callback) { IJobPlanService proxy = GetProxy(); proxy.GetEmployeesByJobIDCompleted += callback; proxy.GetEmployeesByJobIDAsync(jobID); } public void GetTimeSheetViews(int? jobID, int? empID, string weekEnding, EventHandler<GetTimeSheetViewsCompletedEventArgs> callback) { IJobPlanService proxy = GetProxy(); proxy.GetTimeSheetViewsCompleted += callback; proxy.GetTimeSheetViewsAsync(jobID, empID, weekEnding); }
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 allows me to call any WCF service operation using a single method. That way I don’t have to continually write wrapper methods just to call a service operation which really seems pointless to me. 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) while others won’t like it since reflection is involved (I personally don’t view reflection as a big deal here since it’s running on the client-side).
Here’s how it works:
- The CallService method shown next 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.
- 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.
/// <summary> /// Used to call a WCF service operation. /// </summary> /// <typeparam name="T">The type of EventArgs that will be returned by the service operation.</typeparam> /// <param name="callback">The method to call once the WCF call returns (the callback).</param> /// <param name="parameters">Any parameters that the service operation expects.</param> public void CallService<T>(EventHandler<T> 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); }
An example of using the CallService method is shown next:
public void GetAreasByJobID() { _Proxy.CallService<GetAreasByJobIDCompletedEventArgs>((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 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 this application it’s eliminated hundreds of lines of redundant code though (which would’ve grown to 1000s since we’re only 25% of the way through the project) which means we have less to worry about plus this eliminates the time it would’ve taken to write the wrapper methods. Ultimately I view this as a significant benefit to future maintenance since there’s less wrapper code that can get out of sync.
For more information about onsite, online and video training, mentoring and consulting solutions for .NET, SharePoint or Silverlight please visit http://www.thewahlingroup.com/.