Basic Usage

ChannelAdam WCF Library — Version 2 Documentation

Basic Usage

Create a ServiceConsumer with the ServiceConsumerFactory

The first thing you need to understand is that you consume your service operations through the usage of the ChannelAdam.ServiceModel.ServiceConsumer class.

The second thing you need to understand is that the best way to create the ServiceConsumer is by using the Create method on the ChannelAdam.ServiceModel.ServiceConsumerFactory.

In order to use the ServiceConsumerFactory.Create method, simply pass in as a parameter a factory method for creating the service client.

For example:

1IServiceConsumer<IFakeService> service = ServiceConsumerFactory.Create<IFakeService>(() => new FakeServiceClient()));

The ServiceConsumerFactory.Create method returns a IServiceConsumer<TServiceInterface> type. In all further examples, I will use the var keyword instead - such as:

1var service = ServiceConsumerFactory.Create<IFakeService>(() => new FakeServiceClient()));

Alternatively, you can pass in as a string parameter the endpoint configuration name from the service client section of your application’s .config file. For example:

1var service = ServiceConsumerFactory.Create<IFakeService>("BasicHttpBinding_IFakeService")); 

Four Ways to Clean Up the ServiceConsumer

There are four ways in which the ServiceConsumer can be cleaned up:

  1. Implicitly via the Using statement;
  2. Explicitly with the Close method;
  3. Explicitly with the Dispose method; or
  4. Automatically by the Garbage Collector.

1. The Using Statement

The recommended and easiest way to use the ServiceConsumer is with the using statement - because it is a well behaved implementation of IDisposable (unlike Microsoft’s service clients!). The service channel will automatically be correctly disposed and closed or aborted, no matter what happens.

1using (var service = ServiceConsumerFactory.Create<IFakeService>(() => new FakeServiceClient())))
2{
3    ...
4}

2. The Close Method

The ServiceConsumer and underlying channel can be closed immediately by calling the Close method on the ServiceConsumer instance.

1service.Close();

If you want to, you still can immediately call another service operation via that same ServiceConsumer instance, as under the covers, a new service channel will be created seamlessly and automatically.

3. The Dispose Method

The ServiceConsumer and underlying channel can be disposed of immediately by calling the Dispose method on the ServiceConsumer instance.

1service.Dispose();

As per standard IDisposable concepts, you should not attempt to reuse the ServiceConsumer after disposing it.

4. Garbage Collection

If you happen to accidently forget to wrap your ServiceConsumer instance in a Using statement or call the Close method, rest assured that the ServiceConsumer will still be cleaned up! When the ServiceConsumer instance goes out of scope, the .NET Garbage Collector will [eventually] kick in and call its destructor/finalise method, thus correctly cleaning up the service channel and preventing any leaks.

Since there is an indeterminate amount of time before the Garbage Collector kicks in, I would recommend the Using statement approach, as it minimises the number of open channels and other resources currently in use, over the lifetime of your application.

How To Call a Service Operation

There are two ways in which to call a service operation via the ServiceConsumer:

  1. Via the Operations property; or
  2. Via the Consume method.

The Operations Property

The Operations property exposes the interface of your service. It can be used just like the normal service client that you already would be familiar with.

Below is an example of how to call the AddIntegers operation via the Operations property.

1using (var service = ServiceConsumerFactory.Create<IFakeService>(() => new FakeServiceClient())))
2{
3    try
4    {
5        int actualValue = service.Operations.AddIntegers(1, 1); 
6        ...
7    }
8    ...
9}

And below is an example of how to do some exception handling with it.

 1using (var service = ServiceConsumerFactory.Create<IFakeService>(() => new FakeServiceClient())))
 2{
 3    try
 4    {
 5        int actualValue = service.Operations.AddIntegers(1, 1); 
 6        ...
 7    }
 8    catch (FaultException<MyCustomException> fe)
 9    {
10        Console.WriteLine("Service operation threw a custom fault: " + fe.ToString());
11    }
12    catch (FaultException fe)
13    {
14        Console.WriteLine("Service operation threw a fault: " + fe.ToString());
15    }
16    catch (Exception ex)
17    {
18        Console.WriteLine("An unexpected error occurred while calling the service operation: " + ex.ToString());
19    }
20}

There is no need to catch a CommunicationException or TimeOutException and try to perform the Close/Abort pattern, as the underlying channel is dealt with automatically for you by the ServiceConsumer.

The Consume Method

As an alternative to the Operations property, you can call a service operation via the Consume method on the ServiceConsumer instance.

The Consume method returns an instance of IOperationResult<TReturnTypeOfYourOperation> which wraps the result of the operation. This interface has the following helpful properties:

  • TReturnTypeOfYourOperation Value - which gives you access to the return value from the operation;
  • bool HasException - whether there was an exception thrown by the service operation;
  • bool HasNoException - whether there was not an exception thrown by the service operation;
  • bool HasFaultException - whether an exception of type FaultException was thrown by the service operation;
  • bool HasFaultException<OfThisType> - whether an exception of FaultException<OfThisType> was thrown by the service operation; and
  • Exception Exception - the exception that was thrown by the service operation.

Below is an example of how to call the AddIntegers operation via the Consume method.

 1using (var service = ServiceConsumerFactory.Create<IFakeService>(() => new FakeServiceClient())))
 2{
 3	IOperationResult<int> result = service.Consume(operation => operation.AddIntegers(1, 1));
 4
 5    if (result.HasNoException)
 6    {
 7        Console.WriteLine("Result was: " + result.Value);
 8        ...
 9    }
10    ...
11}

And below is an example of how to do some exception handling with IOperationResult.

 1using (var service = ServiceConsumerFactory.Create<IFakeService>(() => new FakeServiceClient())))
 2{
 3    var result = service.Consume(operation => operation.AddIntegers(1, 1));
 4
 5    if (result.HasNoException)
 6    {
 7        Console.WriteLine("Result was: " + result.Value);
 8    }
 9    else
10    {
11        if (result.HasFaultExceptionOfType<MyCustomException>())
12        {
13            Console.WriteLine("Service operation threw a custom fault: " + result.Exception.ToString());
14        }
15        else if (result.HasFaultException)
16        {
17            Console.WriteLine("Service operation threw a fault: " + result.Exception.ToString());
18        }
19        else
20        {
21            Console.WriteLine("An unexpected error occurred while calling the service operation: " + result.Exception.ToString());
22        }
23    }
24}

If you generated async Task methods with your service client, and if you call those async Task methods with Consume(), the task will be executed immediately/synchronously.

The ConsumeAsync Method

Use ConsumeAsync() to asynchronously execute async Task methods on your service client. The syntax is the same as the Consume() example above.

Sample Usage Code

For more sample code, please see SampleUsage.cs.

Please leave below any comments, feedback or suggestions, or alternatively contact me on a social network.

comments powered by Disqus