To call a WCF service method, you typically do the following:
- Create the client proxy object.
- Call the service method.
- Close the connection.
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 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 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.