Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / WCF

Ninject and WCF

5.00/5 (1 vote)
27 May 2013CPOL3 min read 19.2K  
Ninject and WCF

Ninject is a very simple and in the same time powerful IoC container. I used it in few projects and had very little or no problems.

Most of the time, getting instances from Ninject kernel requires simple line with binding expression, or even this is sometimes unnecessary if type is self bindable (i.e., if it is a concrete class with parameterless constructor).

Little harder is getting Ninject to work with WCF. You cannot just bind interfaces types because proxies which implement them are created through .NET mechanism. Luckily, WCF system is very flexible and mostly can be changed/extended with custom functionality.

How we can do that? The best solution is to add new behavior for our WCF services. Behavior is a class that implements IServiceBehavior interface. ApplyDispatchBehavior method accessible through that interface allows our code to change instance provider of our service. Instance provider on the other hand is object with IInstanceProvider interface implementation and GetInstance method. This method is defined in the following way:

C#
object GetInstance(InstanceContext instanceContext);
object GetInstance(InstanceContext instanceContext, Message message);

Inside one of them, we can create instance of our service from Ninject container.

Let us start from the top, with behavior class. It can be applied to service from attribute.

C#
public class NinjectBehaviorAttribute : Attribute, IServiceBehavior
{
	public void AddBindingParameters(ServiceDescription serviceDescription, 
                ServiceHostBase serviceHostBase,
				Collection endpoints, BindingParameterCollection bindingParameters)
	{
	}

	public void ApplyDispatchBehavior(ServiceDescription serviceDescription, 
                ServiceHostBase serviceHostBase)
	{
		Type serviceType = serviceDescription.ServiceType;
		IInstanceProvider instanceProvider = 
               new NinjectInstanceProvider(NinjectServiceLocator.Kernel, serviceType);

		foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)
		{
			foreach (EndpointDispatcher endpointDispatcher in dispatcher.Endpoints)
			{
				DispatchRuntime dispatchRuntime = endpointDispatcher.DispatchRuntime;
				dispatchRuntime.InstanceProvider = instanceProvider;
			}
		}
	}

	public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
	{
	}
}

All interesting things happens inside of ApplyDispatchBehavior method. First NinjectInstanceProvider class is created to which instance of Ninject kernel and our desired service type information is passed. Instance provider is defined as follows:

C#
public class NinjectInstanceProvider : IInstanceProvider
{
	private Type serviceType;
	private IKernel kernel;

	public NinjectInstanceProvider(IKernel kernel, Type serviceType)
	{
		this.kernel = kernel;
		this.serviceType = serviceType;
	}

	public object GetInstance(InstanceContext instanceContext)
	{
		return this.GetInstance(instanceContext, null);
	}

	public object GetInstance(InstanceContext instanceContext, Message message)
	{
		return kernel.Get(this.serviceType);
	}

	public void ReleaseInstance(InstanceContext instanceContext, object instance)
	{
	}
}

Inside second overload of GetInstance method is created actual service instance, through Ninject kernel. Ninject kernel is acquired from simple implementation of service locator. It's just a static class with public read only property with Ninject kernel.

C#
public static class NinjectServiceLocator
{
	public static IKernel Kernel { get; private set; }

	public static void SetServiceLocator(IKernel kernel)
	{
		Kernel = kernel;
	}
}

Instance of kernel is injected into property with SetServiceLocator method after initialization, preferably inside NinjectWebCommon class, which is created in App_Start directory after adding Ninject to project from NuGet.

C#
private static IKernel CreateKernel()
{
	var kernel = new StandardKernel();
	kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
        kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
	RegisterServices(kernel);
	NinjectServiceLocator.SetServiceLocator(kernel);
	return kernel;
}

I decided to go with this solution instead of actual implementation of Microsoft ServiceLocator class to keep it simple, which in fact is working in a similar way.

After creating instance provider object, we apply it to all endpoints inside ApplyDispatchBehavior.

Last thing is to actually register service types inside Ninject. Typically, we are creating all data necessary to make service proxy inside web.config file. WCF channel can be created from such configuration with ChannelFactory class. Let's implement this functionality inside Ninject Provider<> class.

C#
public class ConfigServiceProvider : Provider
{
	protected override TService CreateInstance(IContext context)
	{
		var @interface = typeof(TService);
		var interfaceTypeName = @interface.FullName;
		var endpointsConfig = (ClientSection)ConfigurationManager.GetSection
		("system.serviceModel/client");
		string address = null;
		foreach (ChannelEndpointElement endpoint in endpointsConfig.Endpoints)
		{
			if (endpoint.Contract == interfaceTypeName)
			{
				address = endpoint.Address.OriginalString;
				break;
			}
		}
		var factory = new ChannelFactory<TService>(new WSHttpBinding(), address);
		return factory.CreateChannel();
	}
}

First provider is accessing configuration of all services, then searching inside of configuration for matching interface type name. If it finds one, address of WCF service endpoint is passed to ChannelFactory class which will create service proxy. With such provider, we can do actual type binding inside Ninject module:

C#
public class WcfModule : NinjectModule
{
	public override void Load() { }

	public IBindingWhenInNamedWithOrOnSyntax BindServiceFromConfig()
	{
		return Bind().ToProvider<ConfigServiceProvider>();
	}
}

public class ServicesModule : WcfModule
{
	public override void Load()
	{
		BindServiceFromConfig();
	}
}

WcfModule class can be placed inside some library so we can use it in more than one project. I am sure that not only one of them is using WCF services Smile. ServicesModule on the other hand should be placed inside assembly with services interfaces and loaded from NinjectWebCommon class inside WCF project.

And that is all. WCF web application registers services interfaces inside Ninject, creates kernel and setting its instance inside our custom ServiceLocator class. After that, when service instance is accessed from .NET framework, NinjectBehaviorAttribute does its magic and acquires instance of NinjectInstanceProvider class, which is asking for instance of specified service from kernel. Kernel from its binding creates ConfigServiceProvider through one is created actual instance of proxy, thanks to our configuration.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)