In the 3rd part of a previous series of posts about using dynamic proxies, Ninject and WCF all togehter, I’ve defined a syntax to bind an interface to “auto-disposable WCF client proxies”. When using WCF clients you might need to access the current OperationContext (to add a message header, for example). The implementation in place on the previous post didn’t support this, because the current OperationContext would always be null.
To explicitly create an OperationContext one uses OperationContextScope, but you need to supply a client channel to which the context will be associated. With the previous implementation, the client proxy is created and invoked in the last interceptor of the dynamic proxy, which means there’s no way of creating the OperationContextScope.
To enable using the current OperationContext, I’ve separated the creation and invocation of the WCF proxy. This is accomplished by using two interceptors instead of the previous one. The first one (WcfProxyCreatorInterceptor) is responsible for creating the client proxy and the operation context, but won’t invoke the proxy. Instead, it stores the proxy so that the other interceptor (WcfProxyInvokerInterceptor) can later invoke it.
class WcfProxyCreatorInterceptor<TInterface> : IInterceptor
{
// Per-type cache of channel factories.
private static readonly ChannelFactory<TInterface> ServiceFactory = ChannelFactory();
private static ChannelFactory<TInterface> ChannelFactory()
{
// First available endpoint for TInterface
return new ChannelFactory<TInterface>("*");
}
void IInterceptor.Intercept(IInvocation invocation)
{
using (var channel = (IClientChannel)ServiceFactory.CreateChannel())
{
using (new OperationContextScope(channel))
{
WcfProxyInvokerInterceptor.StoreProxy(channel);
invocation.Proceed();
}
}
}
}
The later interceptor uses the current OperationContext to store the proxy during the current invocation, but it could be stored somewhere else.
class WcfProxyInvokerInterceptor : IInterceptor
{
private const string PROXY_KEY = "__proxy";
internal static void StoreProxy(object proxy)
{
OperationContext.Current.OutgoingMessageProperties[PROXY_KEY] = proxy;
}
public void Intercept(IInvocation invocation)
{
var proxy = OperationContext.Current.OutgoingMessageProperties[PROXY_KEY]
invocation.ReturnValue = invocation.Method.Invoke(proxy, invocation.Arguments); } }
These two interceptors will be the first and the last, respectively, on the dynamic proxy. To that end, the AsWcfProxy method is now implemented as:
public static IBindingToProxyWithInterceptorSyntax<T> AsWcfProxy<T>(this IBindingToProxySyntax<T> binding)
{
return binding
.WithoutTarget<WcfProxyInvokerInterceptor>()
.UsingInterceptor<WcfProxyCreatorInterceptor<T>>();
}
Any other interceptors that are added, will be invoked in between these two, meaning that they will be able to access the current OperationContext.
kernel.Bind<IEcho>()
.ToDynamicProxy(p => p
.AsWcfProxy()
.UsingInterceptor<InterceptorThatUsesOperationContext>());