How They Fell for Lisbon

I found this amazing article about Lisbon on The New York Times. Worth reading =)

IN Lisbon it occurred to me that maybe our favorite places are simply those in which our expectations are routinely exceeded, happenstance cuts in our favor, and it doesn’t matter which fork in the road we take. It leads somewhere we’re happy to be.

Advertisement

Mixin’ up Ninject, Castle Dynamic Proxy and WCF – Revisited

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>());