In this blog post I explain how the Context Preservation extension works and for what it is used.
Imagine that you have a factory to create new objects:
public class MyFactory : IMyFactory { private IResolutionRoot resolutionRoot; public MyFactory(IResolutionRoot resolutionRoot) { this.resolutionRoot = resolutionRoot; } public IFoo CreateFoo() { return this.resolutionRoot.Get<IFoo>(); } }
This factory gets injected into two other object A and B. If you are calling the CreateFoo method you have no knowledge about the context where the new object is created. Therefore you cannot use the contextual features of Ninject. e.g. You can not define that you want to create FooA if calles from A and FooB if called from B. This is where the Context Preservation extension comes into play. It the ContextPreservationModule is loaded the context is preserved. This means that you can add contextual conditions to your bindings and do the scenario explained above like this:
this.Bind<IFoo>().To<FooA>().When(request => request.ParentRequest.ParentRequest.Service == typeof(A)); this.Bind<IFoo>().To<FooB>().When(request => request.ParentRequest.ParentRequest.Service == typeof(B)); public class A { private IMyFactroy factory; public A(IMyFactory factory) { this.factory = factory; } public void Do() { var foo = this.factory.CreateFoo(); } } public class B { private IMyFactroy factory; public B(IMyFactory factory) { this.factory = factory; } public void Do() { var foo = this.factory.CreateFoo(); } }
In this example A creates FooA when Do is called and B creates a FooB.
ContextPreserving Get
There are situations where you bind an interface to a method that uses the kernel to get the implementation. E.g. if you have a service with several interfaces.
public class Service : IServiceA, IServiceB {} this.Bind<Service>().ToSelf().InSingletonScope() this.Bind<IServiceA>().ToMethod(ctx => ctx.Kernel.Get<Service>()); this.Bind<IServiceB>().ToMethod(ctx => ctx.Kernel.Get<Service>());
In this case you lose the context information. This means as above you can’t use conditional bindings anymore. And the second problem is that if the binding fails the stacktrace won’t have the complete injection history anymore. This extension provides ContextPreservingGet to solve these problems.
public class Service : IServiceA, IServiceB {} this.Bind<Service>().ToSelf().InSingletonScope(); this.Bind<IServiceA>().ToMethod(ctx => ctx.ContextPreservingGet<Service>()); this.Bind<IServiceB>().ToMethod(ctx => ctx.ContextPreservingGet<Service>());
BindInterfaceToBinding
The extension provides a even better solution fro the example in the previous chapter. If you have a service with multiple interface you can use BindInterfaceToBinding.
public class Service : IServiceA, IServiceB {} this.Bind<Service>().ToSelf().InSingletonScope(); kernel.BindInterfaceToBinding<IServiceA, Service>(); kernel.BindInterfaceToBinding<IServiceB, Service>();
[…] that you have a basic knowledge about the Context Preservation extension. Consider reading my blog post about the Context Preservation Extension before reading this […]