When we generate (WCF) service proxy class for a service by using svcutil.exe, it creates a proxy that derives from System.ServiceModel.ClientBase<TChannel>. The proxy implements IDisposable and the client code can be wraped inside using statement and guaranteed clean-up in the face of exceptions.
However, the System.ServiceModel.ClientBase<TChannel> class can throw exceptions from its Dispose method, because it internally invokes Close() method which might lead t0 a faulted state. In that case you have to call Abort for clean-up. Most times you are not interested in knowing whether the Dispose fails or not and you just want to have guaranteed clean up of any resources held by the proxy.
Check out this discussion on the WCF forum for why Microsoft implemented the dispose in this way.
To prevent you from writing a lot of code to accomplish this clean-up, I have written a generic GenericServiceProxyAgent class that does it for you.
The idea is that you derive a class from my GenericServiceProxyAgent<TProxy, TChannel> class. Insert your proxy class (that should derive from ClientBase<TChannel>) name for TProxy, and the service interface name for TChannel. The helper class wraps the proxy and doesn't directly expose its methods. From your derived class you can use the protected Proxy property to get access to the service proxy. You should add methods to your derived class that delegate to the proxy.
Create a convenience method to the derived helper that create request messages and unpack response messages. So our helper methods have a different signature than the methods on the proxy class itself.
here is the code snippet.
using System;
using System.Collections.Generic;
using System.ServiceModel;
namespace xxx.Net.Services
{
/// <summary>
/// Generic proxy class for a WCF services.
/// </summary>
/// <typeparam name="TProxy">The type of WCF service proxy to wrap.</typeparam>
/// <typeparam name="TChannel">The type of WCF service interface to wrap.</typeparam>
public class GenericServiceProxyAgent<TProxy, TChannel> : IDisposable
where TProxy : ClientBase<TChannel>, new()
where TChannel : class
{
/// <summary>
/// variable to hold proxy instance
/// </summary>
private TProxy _proxy;
/// <summary>
/// Gets the WCF service proxy wrapped by this instance.
/// </summary>
protected TProxy Proxy
{
get
{
if (_proxy != null)
{
return _proxy;
}
else
{
throw new ObjectDisposedException("GenericServiceProxyAgent");
}
}
}
/// <summary>
/// default constructor.
/// </summary>
protected GenericServiceProxyAgent()
{
_proxy = new TProxy();
}
/// <summary>
/// Disposes the current instance.
/// </summary>
public void Dispose()
{
try
{
if (_proxy != null)
{
if (_proxy.State != CommunicationState.Faulted)
{
_proxy.Close();
}
else
{
_proxy.Abort();
}
}
}
catch (FaultException unknownFault)
{
System.Diagnostics.Debug.WriteLine("An unknown exception was received. " + unknownFault.Message);
_proxy.Abort();
}
catch (CommunicationException)
{
System.Diagnostics.Debug.WriteLine("Service proxy encountred a communication exception and aborted");
_proxy.Abort();
}
catch (TimeoutException)
{
System.Diagnostics.Debug.WriteLine("Service proxy encountred a timeout exception and aborted");
_proxy.Abort();
}
catch (Exception)
{
System.Diagnostics.Debug.WriteLine("Service proxy encountred a unknown exception and aborted");
_proxy.Abort();
throw;
}
finally
{
_proxy = null;
}
}
}
}
Note: Always check the "CommunicationState" before invoking any method on them, this is certainly an additional line of code but certainly a best practise
Happy programming !!!