Following Juwal Lowy’s Programming WCF Services book and great training courses, we know that we are not allowed to reuse a channel after a fault was reported.
This is good however we don’t really feel like writing all the boiler plate code to do that in our own code and close the channel or create a new one after every exception.
We also know that creating WCF Client Proxies is a slow process so we would like to hang on to them for as long as possible (or until they enter a faulted state). We would also like to hang on to the Policy Injection handle that we received for as long as possible to avoid recreating it.
Here is a nice implementation that will do the closing for us however we are still left with disposing the object and creating a new one whenever you need it.
We could implement a policy and inject it in using the Policy Injection however that would mean we would need to reset somehow the object handle inside the PolicyInjection object. Way to complicated when we could all handle it up-front.
To follow the pattern to emitting code (it’s easy to emit and once tested it always works). No need for boring and error prone copy&paste.
The base class for the wrapper class
This would a good base abstract class that we can inherit for all our wrapper classes.
I also included MarshalByRefObject to allow us to easily use these wrappers with EntLib Policy Injection Block.
/// <summary>
/// Class that can be used with PolicyInjection. Dynamically generated classes will inherit from this class.
/// </summary>
public abstract class WCFAbstractClientProxyWrapper<T> : MarshalByRefObject where T : class
{
protected T cachedProxy;
private readonly string configName;
protected WCFAbstractClientProxyWrapper(string configName)
{
this.configName = configName;
}
/// <summary>
/// Called to retrieve a cached instance of the proxy.
/// </summary>
protected T Proxy
{
get
{
AssureProxy();
return cachedProxy;
}
}
/// <summary>
/// Close the proxy because it was fauled.
/// http://bloggingabout.net/blogs/erwyn/archive/2006/12/09/WCF-Service-Proxy-Helper.aspx
/// </summary>
protected void CloseProxyBecauseOfException()
{
if (cachedProxy != null)
{
ICommunicationObject wcfProxy = cachedProxy as ICommunicationObject;
try
{
if (wcfProxy != null)
{
if (wcfProxy.State != CommunicationState.Faulted)
{
wcfProxy.Close();
}
else
{
wcfProxy.Abort();
}
}
}
catch (CommunicationException)
{
wcfProxy.Abort();
}
catch (TimeoutException)
{
wcfProxy.Abort();
}
catch
{
wcfProxy.Abort();
throw;
}
finally
{
cachedProxy = null;
}
}
}
/// <summary>
/// Create a new proxy if there is none already in use.
/// If the previous proxy was faulted, it will be nulled and a new proxy is created
/// </summary>
private void AssureProxy()
{
if (cachedProxy == null)
{
cachedProxy = WCFClientProxy<T>.GetInstance(configName);
}
}
}
This class respects the Erwyn’s recommendations about the correct closing of a faulted WCF Channel.
The wrapper class
In order to allow our code to simply reuse an existing object even if it’s faulted, we need to wrap an existing client proxy into another class that implements our interface and does all this boiler plate.
For our current interface:
[ServiceContract()]
public interface IService1
{
[OperationContract]
[FaultContract(typeof(Exception))]
string MyOperation1(string arg1, int arg2);
[OperationContract]
void MyOperation2(string value);
}
This would be the wrapper class:
public class ClientProxyWrapperIService1 : WCFAbstractClientProxyWrapper<IService1>, IService1
{
public ClientProxyWrapperIService1(string configName)
: base ( configName )
{
}
#region IService1 Members
public string MyOperation1(string arg1, int arg2)
{
try
{
return Proxy.MyOperation1(arg1, arg2);
}
catch
{
CloseProxyBecauseOfException();
throw;
}
}
public void MyOperation2(string value)
{
try
{
Proxy.MyOperation2(value);
}
catch
{
CloseProxyBecauseOfException();
throw;
}
}
#endregion
}
Simple implementation that for every call will try to close the proxy if it was faulted and then create a new one next time it needs it.
There is a fair bit of code that we would need to type for each method so lets try to code emit this method.
protected override void GenerateMethodImpl(System.Reflection.MethodInfo method, Type[] parameterTypes, System.Reflection.Emit.ILGenerator iLGenerator)
{
bool hasReturn = !IsVoidMethod(method);
if (hasReturn)
{
// declare a variable to contain the return type
// string returnValue;
iLGenerator.DeclareLocal(method.ReturnType);
}
// try {
Label tryLabel = iLGenerator.BeginExceptionBlock();
{
// this
iLGenerator.Emit(OpCodes.Ldarg_0);
// Get the details Property of the ClientBase
MethodInfo proxyProperty = GetMethodFromBaseClass("get_Proxy");
// Get the channel: "base.Channel<TInterface>."
iLGenerator.EmitCall(OpCodes.Call, proxyProperty, null);
// Prepare the parameters for the call
ParameterInfo[] parameters = method.GetParameters();
for (int index = 0; index < parameterTypes.Length; index++)
{
iLGenerator.Emit(OpCodes.Ldarg, (int)(((short)index) + 1));
}
// Call the Proxy via the interface
iLGenerator.Emit(OpCodes.Callvirt, method);
if (hasReturn)
{
// returnValue = result of the function call
iLGenerator.Emit(OpCodes.Stloc_0);
}
}
// catch {
{
iLGenerator.BeginCatchBlock(typeof(object));
iLGenerator.Emit(OpCodes.Pop); // get the exception from the stack
// this
iLGenerator.Emit(OpCodes.Ldarg_0);
//call base.CloseProxyBecauseOfException();
MethodInfo closeProxyMethod = GetMethodFromBaseClass("CloseProxyBecauseOfException");
iLGenerator.Emit(OpCodes.Call, closeProxyMethod);
// throw;
iLGenerator.Emit(OpCodes.Rethrow);
}
// }
iLGenerator.EndExceptionBlock();
if (hasReturn)
{
// return returnValue;
iLGenerator.Emit(OpCodes.Ldloc_0);
}
// Thanks, all done
iLGenerator.Emit(OpCodes.Ret);
}
Plug this together with the Dynamic WCF Client Proxy generator from yesterday and we can now have this easy wrapper:
/// <summary>
/// Returns a new instance for a client proxy over the specified interface with the specified config name used for initialization.
/// </summary>
public static TInterface GetWrappedInstance(string configName)
{
// Build the type
WCFProxyWrapperClassBuilder<TInterface> builder = new WCFProxyWrapperClassBuilder<TInterface>();
Type type = builder.GenerateType();
// Create new instance
TInterface instance = (TInterface)Activator.CreateInstance(type, new object[] { configName });
return instance;
}
It can’t get any simpler.
If we also want to use the EntLib Policy injection to have nice control and to be able to cache the calls to this services we could then add a new method:
/// <summary>
/// Returns a new instance for a client proxy over the specified interface with the specified config name used for initialization.
/// </summary>
public static TInterface GetPolicyInstance(string configName)
{
// Create new instance
TInterface instance = WCFProxyWrapperClassBuilder<TInterface>.GetInstance(configName);
return PolicyInjection.Wrap<TInterface>(instance);
}
How to we use the proxy wrapper
Because our actual proxy now has a wrapper that will correctly close it when it becomes faulted we don’t really need to care about it anymore and we can simply reuse it even after multiple faults.
IService1 service = WCFClientProxy<IService1>.GetWrappedInstance("Service1");
for (int i = 0; i < 10; i++)
{
try
{
Console.WriteLine(i + " ClientTime:" + DateTime.Now.ToString("HH:MM:ss:ffff") + " result -> " + service.MyOperation1("a", 0));
}
catch (Exception ex)
{
Console.WriteLine(i + " " + ex.Message);
}
Thread.Sleep(1000 * rand.Next(20));
}
This time really it won’t get any simpler.
Performance
Creating the wrapper and the proxy:
The dynamic wrappers and the dynamic proxies are emitted only once the very first time you use them. The performance impact is small simply because code emitting is relatively fast and we only use reflection to look at a public interface. Once the wrapper and proxy are generated they types are stored in a dictionary that is referenced every time we need a new wrapper or proxy.
Calling the service via the wrapper and proxy:
Well considering all we introduce in the call is an extra lookup in the dictionary to search for the correct types that we need to instantiate and we only do that when you create them the overall impact is not big.
The wrapper code you have to write anyway in a way or another in your code. The proxy code is the code you would get generated or hand written in the same way.
There are no reflective calls at any time after the two types were generated so the call stacks are simple and not longer than what you would expect. So performance wise it should make the difference. Just give it a try.
I have to say this was one of the nicest piece of code I’ve wrote in ages.
Download code and demos here.