Ninject.Extension.ContextPreservation explained

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

About the author

Remo Gloor

My name is Remo Gloor and I’m working as a software architect at bbv Software Services AG in Zug, Switzerland. My first expiriences with computers were a a little boy with basic programming on a C64, later Pascal an C on an Intel 8080. After finishing my study in software engineering I started working with C#.

Currently, I'm one of two Main Developers of the well known Ninject IoC containers. My other interests beside Ninject are TDD, Scrum and software architecture in general.

1 comment

By Remo Gloor

Recent Posts