Skip to content

Instantly share code, notes, and snippets.

@a-h
Created March 17, 2015 10:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save a-h/c4fc17bafb8345e6ef1d to your computer and use it in GitHub Desktop.
Save a-h/c4fc17bafb8345e6ef1d to your computer and use it in GitHub Desktop.
ChannelFactory Cache and the Ninject Binding Extension Method
// Modified from examples at luisfsgoncalves.wordpress.com/2012/02/28/mixin-up-ninject-castle-dynamic-proxy-and-wcf-part-iii/
// to use a channel factory cache.
public static class ToWcfClientExtensions
{
public static IBindingWhenInNamedWithOrOnSyntax<T> ToWcfClient<T>(this IBindingToSyntax<T> syntax) where T : class
{
return syntax.ToMethod(ctx => ctx.Kernel
.Get<ProxyGenerator>()
.CreateInterfaceProxyWithoutTarget<T>(new WcfProxyWithDisposalInterceptor<T>()));
}
}
public class WcfProxyWithDisposalInterceptor<TInterface> : IInterceptor where TInterface : class
{
void IInterceptor.Intercept(IInvocation invocation)
{
if (invocation.Method.Name.Equals("Dispose", StringComparison.Ordinal))
{
throw new InvalidOperationException("Dispose invoked on WcfProxyWithDisposalInterceptor");
}
// I use a global ChannelFactory cache instead of caching using the Configuration System.
using (var channel = (IDisposable)ChannelFactoryCache.CreateChannel<TInterface>())
{
invocation.ReturnValue = InvokeMethod(invocation, channel, invocation.Arguments);
}
}
private static object InvokeMethod(IInvocation invocation, object channel, object[] arguments)
{
try
{
return invocation.Method.Invoke(channel, arguments);
}
catch (TargetInvocationException ex)
{
// Preserve stack trace
var stackTrace = typeof(Exception).GetField("_remoteStackTraceString", BindingFlags.Instance | BindingFlags.NonPublic);
if (stackTrace != null)
{
stackTrace.SetValue(ex.InnerException, ex.InnerException.StackTrace + Environment.NewLine);
}
throw ex.InnerException;
}
}
}
public static class ChannelFactoryCache
{
private static Dictionary<Type, Tuple<EndpointAddress, object>> cache = new Dictionary<Type, Tuple<EndpointAddress, object>>();
public static void Add<TInterface>(Uri uri, Binding binding, List<IEndpointBehavior> behaviors)
{
var endpointAddress = new EndpointAddress(uri);
var factory = new ChannelFactory<TInterface>(binding);
if (behaviors != null)
{
foreach (var behavior in behaviors)
{
factory.Endpoint.Behaviors.Add(behavior);
}
}
if (!cache.ContainsKey(typeof(TInterface)))
{
cache.Add(typeof(TInterface), new Tuple<EndpointAddress, object>(endpointAddress, factory));
}
}
public static TInterface CreateChannel<TInterface>() where TInterface : class
{
var data = cache[typeof(TInterface)];
return (data.Item2 as ChannelFactory<TInterface>).CreateChannel(data.Item1) as TInterface;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment