Sunday, October 30, 2011

Calling WCF Service Methods With One Line Of Code

While WCF makes creating services (Web, TCP, etc) incredibly easy, it's client functionality, in my opinion, is not as easy to use.  Most of this has to do with calling WCF service methods, and the method in which clients must be created.

To call a WCF service method, you typically do the following:
  • Create the client proxy object.
  • Call the service method.
  • Close the connection. 
Both the first step and the last step can cause problems.  It is recommended that you do not share proxy objects, meaning, you can't create a single proxy object to use throughout your class or program.  You must create a proxy object every time you want to call a service method. The last step (closing the connection) is where most difficulties arise.  For example, suppose we have a WFC web service that exposes data from the Northwind database.  We might have a method that gets all the products by a category ID.  If we have a WinForms application that binds this data to a Grid View control, our code to call the web service might look like this (assuming we created the proxy class with the Visual Studio Add Service Reference menu option:


On the last line, we have to remember to close the connection.  Remembering to do this is similar to remembering to de-allocate dynamic memory, or remembering to call IUnknown.Release() in the old world of COM.  It's just not something modern developers want to worry about.  The proxy generated by the Add Service Reference menu implements IDisposable so you could create the client in a using statement so the client is closed after the call.  This could make cleanup easier, however there is a well known issue with using the using statement with WCF client proxies that is described here.  Microsoft actually recommends you NOT use the using statement with a WCF client.

So, how can we make this process easier?  By using generics, lambdas, and Expressions, we can create a client library that does all the cleanup for us, and allows us to call a WCF service method in one line of code. This post will show how to create an object that can be used to easily call any type of WFC service, such as Web services, TCP services, and the link.  In a later post, I will show how to create a second object that can be used to specifically call RESTful web services.

To do this, we can create two interfaces:
  • IWCFServiceChannel<TServiceInterface>
  • IWCFServiceCaller<TServiceInterface>
Here is the definition of IWCFServiceChannel<TServiceInterface>:
 


It contains two methods.  The first is used to create a proxy to a web service defined by the interface TServiceInterface type.  The second, Close(), is used to close an open connection. Objects implementing this interface are used to manage WFC Channel objects.


Here is the defiintion of IWCFServiceCaller<TServiceInterface>:









This interface contains a single method named CallServiceMethod, whose purpose it to call a method on the type TServiceInterface, via the supplied Expression object.  Note the parameter is supplied as an Expression<> instead of a Func<> in order to facilitate creating an implementation of this interface that can be used to call a RESTful web service.

Let's look at the implementation of each.  First, the class WCFServiceChannel, which implements IWCFServiceChannel.  First, let's look at the constructor:









The parameters are all used to configure the WCF ChannelFactory object used internally by the GetWebServiceProxy() method.  The first, bindingName, is the name of a binding configuration in the <system.ServiceModel> section of an app.config or web.config file.  This configuration can be used to set properties of the binding such as SSL security, received message size, etc. Uri is, obviously, the uri of the WFC service.  The third, bindingType, is the type of binding to create, i.e. basicHttpBinding, wsHttpBinding, etc.  The last two parameters, userName and password, can be used to supply credentials to services that require them.

Next, here is the implementation of the GetWebServiceProxyMethod():

First, note that _channelFactory is a private member variable defined as follows.  It is an instance of the ChannelFactory<T> object that is used to create the WFC Channel used for communication with the service.




Lines 73-84 check the _bindingType supplied in the constructor and create the appropriate binding, using the supplied _url and _bindingName from the configuration file.  If supplied, the credentials are added to the _channelFactory, and then the channel is created and returned as an instance of TServiceInterface.

Now let's look at the implementation of IWCFServiceCaller.  Here is the implementation of CallServiceMethod:






The implementation is pretty straight forward.  Line 69 calls the _serviceChannel object (an instance of WCFServiceChannel supplied via a property on the WCFServiceCaller object) to get the client proxy.  Line 72 compiles the supplied Expression object parameter and invokes the resulting function, supplying the client object as a parameter.  The return type of the resulting function is the same as the return type of the method being called on the client proxy.  An example will help to clarify this, but first note that in the finally block of try block, the _serviceChannel Close() method is called, ensuring that your channel is always closed for you and you don't have to worry about cleanup after a service call.

Finally, putting this all together, here is an example of how you call use the WCFServiceChannel and the WCFServiceCaller to call the GetProducts() method defined on our imaginary Northwind web service:






Lines 46-50 create the WCFServiceChannel and WCFServiceCaller.  They are created within the same function as they are used, but since the WCFServiceCaller takes care of connection management for you by creating a new WCFServiceChannel on each call and ensuring the connection is closed, you could create and configure these two objects in a constructor or initialization function and share them throughout your class or application, something that you cannot easily do with a standard WCF client.

Lines 52-53 show how to use the WCFServiceCaller to call a method on a WCF service.  The supplied lambda expression takes an instance of INorthwindService (as specified in the declaration of the serviceChannel and serviceCaller objects) and calls the GetProducts method.  This lambda itself is then compiled and executed by the implementation of CallServiceMethod().

So, with a little work and creating a few classes, you can create a WCF service client that takes care of the initialization and cleanup for you, and allows you to call a WCF service method with only one line of code. In my next post, I'll show how you can create another implementation of IWCFServiceCaller specifically for calling RESTful web services.