A Lambda Expression Pattern for WCF Clients

I’ve sometimes ended up repeating the same blocks of boilerplate code when consuming WCF services: open the connection; do work; close the connection; wrap it all in a try-catch; close the exception differently depending on the type of exception thrown. I wanted to put the boilerplate code somewhere else to keep the rest of my service-calling code as clean and DRY as possible. This post discusses an approach I’ve used to achieve it.

Download the example project

Screenshot of server and client applications

There were a few key things I wanted from the pattern:

  • I don’t want to worry about the connection code. I just want to call the service and move on.
  • Exceptions must bubble up—unmodified—so that they can be handled appropriately.
  • If an exception does get thrown, the connection needs to be closed or aborted as appropriate. It’s important to do this correctly since connections left hanging around can very quickly kill your application—for more on this, see the MSDN article: Expected Exceptions.

I decided to use a lambda expression pattern so I could replace code like this:

Code snippet

…with something like this:

Code snippet

It’s worth pointing out that I prefer to use a shared services assembly if it’s feasible to do so, and that’s the approach I’ve taken in this example. It’s a topic for another blog post, but things can get complicated with svcutil-generated proxies if you have DataContract classes that are shared across multiple endpoints.

The example shows a really simple service that takes a name and returns a greeting such as “Hello, Mike!” The service contract looks like this:

[ServiceContract]
public interface IGreetingService
{
    [OperationContract]
    string SayHello(string name);
}

If you’ve made it this far, I expect you can guess what the implementation looks like. The example solution includes a really simple Console application to host the service on TCP port 8000 using the following WCF configuration:

<system.serviceModel>
  <services>
    <service name="GreetingServices.GreetingService">
      <endpoint
        address="net.tcp://localhost:8000/GreetingService"
        binding="netTcpBinding"
        contract="GreetingServices.IGreetingService"/>
    </service>
  </services>
</system.serviceModel>

On the client side, there’s a similar TCP/IP binding to the service:

<system.serviceModel>
  <client>
    <endpoint
      name="GreetingServices.IGreetingService"
      address="net.tcp://localhost:8000/GreetingService"
      binding="netTcpBinding"
      contract="GreetingServices.IGreetingService"/>
  </client>
</system.serviceModel>

Now for the important bit: the services will be called using a lambda expression, so the first thing is to declare a delegate through which the client logic will be passed.

public delegate void DoWithServiceDelegate(T serviceClient);

Next, a “Services” class will present the proxy into the service. It contains a private method that sends a generic delegate into a generic service endpoint:

private static void WithServiceClient<T>(T serviceClient, DoWithServiceDelegate<T> serviceDelegate)
{
    try
    {
        serviceDelegate(serviceClient);
        ((IClientChannel)serviceClient).Close();
    }
    catch (TimeoutException)
    {
        // Abort the connection if it times out
        ((IClientChannel)serviceClient).Abort();
        throw;
    }
    catch (CommunicationException)
    {
        // Abort the connection if there's a connection-level failure
        ((IClientChannel)serviceClient).Abort();
        throw;
    }
    catch (Exception)
    {
        // The connection should be valid for other exception types, so close it normally
        ((IClientChannel)serviceClient).Close();
        throw;
    }
}

The key points covered by the above code are:

  • Make sure the connection gets closed properly, even if something throws an exception.
  • Allow exceptions to bubble up to the surface intact.

Finally, the service proxy is presented through a public method:

public static void WithGreetingService(DoWithServiceDelegate<IGreetingService> serviceDelegate)
{
    // Create the connection to IGreetingService
    var channelFactory = new ChannelFactory<IGreetingService>("*");
    IGreetingService channel = channelFactory.CreateChannel();

    // Execute the delegated logic
    WithServiceClient(channel, serviceDelegate);
}

Each new service will need its own public method similar to the WithGreetingService(…) method but, unless project contains a really high number of endpoints, this shouldn’t become too cumbersome. To make a really simple, one-line call to the service:

Services.WithGreetingService(service => service.SomeMethod(…));

– Mike Clift

Leave a Reply

Your email address will not be published. Required fields are marked *