PS retira PL 118

Quote

“face aos sinais públicos, designadamente do PSD, de não viabilização desse caminho, o PS decidiu retirar o PL118”

Parece que vão trabalhar numa nova versão.. oh well, pelos menos não avança nos moldes em que estava! [Mais info]

Advertisements

Mixin’ up Ninject, Castle Dynamic Proxy and WCF – Part IV

On the previous post of this series we got a Ninject syntax to bind service contracts to dynamic WCF clients using Castle dynamic proxy. To complete the series of posts I’ll describe a way to also use dynamic proxies and interceptors on the server side.

Ninject has an extension for using DI during WCF services activation (Ninject.Extensions.Wcf, also available as a NuGet package). The extension includes a service host factory and a custom application that should be used to enable DI on service activation. The service factory should be used on the services that need DI:

<%@ ServiceHost
    Service="Injection.DynamicProxy.Wcf.Service.EchoService"
    CodeBehind="EchoService.svc.cs
    Factory="Ninject.Extensions.Wcf.NinjectServiceHostFactory" %>

and the application is used to supply the Kernel:

    public class Global : NinjectWcfApplication
    {
        protected override IKernel CreateKernel()
        {
            var kernel = new StandardKernel();
            // ...
            return kernel;
        }
    }

Ninject extensions use the following strategy to implement DI on service activation:

  • NinjectWcfApplication creates the Kernel on Application_Start and then registers a binding from ServiceHost (WCF) to a built-in implementation. This is done on the RegisterCustomBehavior method, which can be overridden by the application to bind a custom ServiceHost implementation.
  • When asked to create a ServiceHostNinjectServiceHostFactory relies on the kernel to get an implementation (the reference to the kernel created by the application is at a known shared static location).
  • The built-in ServiceHost implementation adds a behavior that sets the instance providers on the different service endpoints to an instance of NinjectInstanceProvider, passing the type of the service defined on the svc file. 
  • When asked to create an instance of the service, NinjectInstanceProvider relies on the kernel to get it.

My first approach was trying to define a binding from the service class to a dynamic proxy, but I found two problems: first, I’d need to use class proxies instead of interface proxies, which means that the syntax presented on the previous posts would need to be extended. Second, the target of the dynamic proxy would be the service class itself but I couldn’t find a clean way to distinguish the top level request (made by NinjectInstanceProvider) from the one that should actually create the service instance (made by the syntax developed on the previous posts). Ninject ended up on a recursive loop always trying to resolve the service class to a dynamic proxy.

The next attempt was putting the service contract interface instead of the implementing class on the svc file, thinking that this would be the type that NinjectInstanceProvider ends up requesting to the kernel. But it seems that WCF doesn’t allow interface types on the Service attribute of the svc file, so another solution was needed.

(Hacking mode on) What I really needed was to change the type that is requested to the kernel to the service interface. I can’t specify it directly, but it can easily be found by looking into the interfaces implemented by the service class, namely those that are marked with the ServiceContract attribute. This could be done by using a different instance provider, but unfortunately the Ninject WCf extensions create instances of NinjectInstanceProvider instead of asking the kernel to do so. The solution I found was to use a custom ServiceHost and use a similar approach, with the difference that the behavior creates NinjectInstanceProvider instances by passing the service interface instead of the service class:

class ServiceContractNinjectInstanceProviderBehavior : IServiceBehavior
{
	public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
	{
		var serviceContract = serviceDescription.ServiceType
			.GetInterfaces()
			.Single(i => i.GetCustomAttributes(typeof(ServiceContractAttribute), false).Length == 1);
		var ninjectInstanceProvider = new NinjectInstanceProvider(serviceContract);

		var endpointDispatchers = serviceHostBase.ChannelDispatchers
			.OfType<ChannelDispatcher>()
			.SelectMany(channelDispatcher => channelDispatcher.Endpoints);

		foreach (var endpointDispatcher in endpointDispatchers)
		{
			endpointDispatcher.DispatchRuntime.InstanceProvider = ninjectInstanceProvider;
		}
	}
}

The behavior is added by a custom ServiceHost that needs to be registered on the kernel. That can be done by defining a custom Ninject WCF application that extends the existing one:

public abstract class ServiceContractNinjectWcfApplication : NinjectWcfApplication
{
	protected sealed override void RegisterCustomBehavior()
	{
		Kernel.Bind<ServiceHost>().To<ServiceContractNinjectServiceHost>();
	}
}

And that’s it! We can now register bindings for the services using the syntax from the previous posts:

            kernel.Bind<IEcho>()
                .ToDynamicProxy(c => c.WithTarget<EchoService>().UsingInterceptor<MyInterceptor>())
                .InRequestScope();

(Hacking mode off) This posts ends the series. Using dynamic proxies on server side, especially with this hacks in place, probably isn’t something you need that often. However, I think that they can be really helpful when used on WCf client scenarios.

The VS 2010 solution with the source code for the series is available here.