Skip to content

Instantly share code, notes, and snippets.

@danielmarbach
Created May 18, 2011 22:30
Show Gist options
  • Save danielmarbach/979743 to your computer and use it in GitHub Desktop.
Save danielmarbach/979743 to your computer and use it in GitHub Desktop.
Client proxy interceptor for WCF and dynamic proxy
public class ClientProxyInterceptor : IInterceptor
{
private readonly Func<ICommunicationObject> proxyCreator;
private readonly Type typeToProxy;
private ICommunicationObject proxyInstance;
public ClientProxyInterceptor(Func<ICommunicationObject> proxyCreator, Type typeToProxy)
{
this.typeToProxy = typeToProxy;
this.proxyCreator = proxyCreator;
}
public ICommunicationObject CachedProxy
{
get
{
this.EnsureProxyExists();
return this.proxyInstance;
}
set
{
this.proxyInstance = value;
}
}
public void Intercept(IInvocation invocation)
{
try
{
invocation.ReturnValue = invocation.Method.Invoke(this.CachedProxy, invocation.Arguments);
}
catch (TargetInvocationException ex)
{
Exception innerException = ex.InnerException;
throw innerException;
}
finally
{
this.CloseProxy(invocation.Method);
}
}
private void EnsureProxyExists()
{
if (this.proxyInstance == null)
{
this.proxyInstance = this.proxyCreator();
}
}
private void CloseProxy(MethodInfo methodInfo)
{
var wcfProxy = this.CachedProxy;
if (wcfProxy != null && this.typeToProxy.IsAssignableFrom(methodInfo.DeclaringType))
{
if (wcfProxy.State == CommunicationState.Faulted)
{
this.AbortCommunicationObject(wcfProxy);
}
else if (wcfProxy.State != CommunicationState.Closed)
{
try
{
wcfProxy.Close();
this.CachedProxy = null;
}
catch (CommunicationException)
{
this.AbortCommunicationObject(wcfProxy);
}
catch (TimeoutException)
{
this.AbortCommunicationObject(wcfProxy);
}
catch (Exception)
{
this.AbortCommunicationObject(wcfProxy);
throw;
}
}
}
}
private void AbortCommunicationObject(ICommunicationObject wcfProxy)
{
wcfProxy.Abort();
this.CachedProxy = null;
}
}
public class ServicesInitializer
{
public override void Start()
{
foreach (Type serviceType in this.ServiceTypeProvider.Types)
{
var binding = this.CreateBinding();
var address = this.CreateEndpointAddress(serviceType);
var endpointAddress = new EndpointAddress(address);
var proxyCreatorType = this.MakeGenericType(serviceType);
var proxyCreator = this.GetProxyCreator(proxyCreatorType, binding, endpointAddress);
Type type = serviceType;
this.kernel.Bind(serviceType).ToMethod(
ctx => this.proxyGenerator.CreateInterfaceProxyWithoutTarget(type, new[] { typeof(IContextChannel), }, this.CreateInterceptor(proxyCreator, type)));
}
}
public override void Shutdown()
{
foreach (IChannelFactory channelFactory in this.proxyInstanceCreatorCache.Values)
{
channelFactory.Close();
}
}
protected virtual IInterceptor CreateInterceptor(IChannelFactory proxyCreator, Type serviceType)
{
dynamic channelFactory = proxyCreator;
return new ClientProxyInterceptor(() => (ICommunicationObject)channelFactory.CreateChannel(), serviceType);
}
protected virtual IChannelFactory CreateProxyInstanceCreator(Type genericProxyCreatorType, Binding binding, EndpointAddress endpointAddress)
{
IChannelFactory proxyInstanceCreator = (IChannelFactory)Activator.CreateInstance(genericProxyCreatorType, binding, endpointAddress);
return proxyInstanceCreator;
}
private IChannelFactory GetProxyCreator(Type genericProxyCreatorType, Binding binding, EndpointAddress endpointAddress)
{
IChannelFactory proxyInstanceCreator;
if (!this.proxyInstanceCreatorCache.TryGetValue(genericProxyCreatorType, out proxyInstanceCreator))
{
proxyInstanceCreator = this.CreateProxyInstanceCreator(genericProxyCreatorType, binding, endpointAddress);
this.proxyInstanceCreatorCache.Add(genericProxyCreatorType, proxyInstanceCreator);
}
return proxyInstanceCreator;
}
private Type MakeGenericType(Type serviceType)
{
if (!serviceType.IsInterface)
{
throw new InvalidOperationException("Type returned from proxy type provider must not be concrete type!");
}
Type genericProxyType;
if (!this.genericTypeCache.TryGetValue(serviceType, out genericProxyType))
{
genericProxyType = typeof(ChannelFactory<>).MakeGenericType(new[] { serviceType });
this.genericTypeCache.Add(serviceType, genericProxyType);
}
return genericProxyType;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment