Click here to Skip to main content
15,881,715 members
Articles / Programming Languages / C#

The story about Ninja, Unity Application Block and Contextual Dependency Injection

Rate me:
Please Sign up or sign in to vote.
4.47/5 (10 votes)
30 Nov 2008CPOL7 min read 35.4K   109   32   2
This article describes how get contextual dependency injection in an application using Unity Application Block

Introduction

To write this article, I had a conversation with one of the Italian software architects, namely with Giorgio Bozio. The idea of Ninja is his. The topic for discussion was the question of how to use NInject for implementation of Dependency Injection (DI) depending on the context. Now I suggest this decision which I use every day.

Problem Domain

There are entities in our problem domain: Ninja, SuperNinja, Sword and Shuriken. On the basis of them, we will develop the following classes and interfaces:

C#
interface IWeapon
{
    void Use();
} 
C#
class Sword : IWeapon
{
    #region IWeapon Members

    public void Use()
    {
        Console.WriteLine("Sword was used.");
    }

    #endregion
} 
C#
class Shuriken : IWeapon
{
    #region IWeapon Members

    public void Use()
    {
        Console.WriteLine("Shuriken was used.");
    }

    #endregion
} 
C#
class Ninja
{
    [Dependency]
    public IWeapon Weapon { get; set; }
}
C#
class SuperNinja
{
    [Dependency]
    public IWeapon SuperWeapon { get; set; }
}

I'll give some comments for the source code. The weapon classes implement common IWeapon interface, but Ninja and SuperNinja classes aren't linked. Many people can object that only ninja is going to make super ninja, and here we must apply such paradigm of OOP as inheritance. But I can object that super ninja can be born only, but ninja can't become a super ninja, and besides inheritance increases coupling in architecture and it is recommended to avoid it. But in this case, it isn't important. Further the attention involves attribute Dependency. It points out that the property will be used DI.

Dependency Injection

Now we will consider application DI. For this, we will use one of the many frameworks Unity Application Block version 1.2. It’s non-essential, it’s possible to use both StructureMap and Castle Windsor. Simply Giorgio Bozio had problems with NInject and he had asked to give an example with the framework that I used.

The code looks as follows:

C#
class Program
{
    static void Main(string[] args)
    {
        IUnityContainer container = new UnityContainer();
        container.RegisterType<IWeapon, Sword>();

        var ninja = container.Resolve<Ninja>();
        ninja.Weapon.Use();

        var superNinja = container.Resolve<SuperNinja>();
        superNinja.SuperWeapon.Use();

        Console.ReadKey();
    }
} 

In the beginning the container of dependences is created, and dependences are specified. Here it is obviously set that objects will receive Sword instance by using of IWeapon interface. Further Ninja ? SuperNinja instances are created by means of the container. At creation the properties marked as Dependency will have values of type Sword. That is there will be DI, to the help where there will be an interface substitution by real objects implementing it.

The code output will be such:

Ninja_1.png

Let's explain the result. Ninja and superNinja used the weapon and it had appeared as Sword. It was followed as expected, as other dependences haven't been set by us.

Vulnerable Contextual Dependency Injection

There is one problem: superNinja must have the kind of SuperWeapon. Let's give to him as a weapon Shuriken. Now we will set this dependence, but at once we will notice that only superNinja can have Shuriken. This is Contextual Dependency Injection. In other words, the injection is depending on a context of work of object for which it is applied.

There are two most simple ways to make this work.

The first way is creation of the named dependence. The code takes the following form:

C#
class Program
{
    static void Main(string[] args)
    {
        var container = new UnityContainer();
        container.RegisterType<IWeapon, Sword>();
        container.RegisterType<IWeapon, Shuriken>(typeof(SuperNinja).ToString());

        var ninja = container.Resolve<Ninja>();
        ninja.Weapon.Use();

        var superNinja = new SuperNinja();
        superNinja.SuperWeapon = 
            container.Resolve<Shuriken>(typeof(SuperNinja).ToString());
        superNinja.SuperWeapon.Use();

        Console.ReadKey();
    }
}

Note we have set the second dependence for the same interface. This dependence is named. It is possible to choose any name, but we will choose it with sense - typeof(SuperNinja).ToString(), i.e. dependence for SuperNinja. The code has a little exchanged in place of DI, we don't use default injection, but use an injection with a certain name. It coincides that it has been specified in new dependence.

Disadvantage of this method is that it is necessary to always remember that the named injection is used and don't forget to point a name while using. It is possible to overcome this disadvantage as follows: always use the called injections.

Another disadvantage is that the creation of object and injection instructions has become complicated. The decision can be the same, as well as at the previous disadvantage.

That result which we also achieved was as follows:

Ninja_2.png

The second way is the creation of the nested container. The code is as shown below:

C#
class Program
{
    static void Main(string[] args)
    {
        var container = new UnityContainer();
        container.RegisterType<IWeapon, Sword>();

        var childContainer = container.CreateChildContainer();
        childContainer.RegisterType<IWeapon, Shuriken>();

        var ninja = container.Resolve<Ninja>();
        ninja.Weapon.Use();

        var superNinja = childContainer.Resolve<SuperNinja>();
        superNinja.SuperWeapon.Use();

        Console.ReadKey();
    }
}

Following changes have been made: the nested container of dependences has been created and the way of setting of an injection is changed. From the code, it is visible that the nested container redefines dependence of the parent container.

Disadvantage of this method is that it is necessary to set other container for the creation of dependences and not forget to use it. The decision consists in moving of code of creation the nested container as it is possible to be more close to a place of its direct use.

Let's bring a certain intermediate result. It was offered two ways of the decision of a problem with contextual DI. They have both the advantages and the disadvantages. It is necessary to underline that disadvantages can be smoothed by application of a configuration file. All dependences which are set in the source code can be set as declarative. But there is one fundamental disadvantage – injection setting isn't always set only for SuperNinja.

We can make the following, for example:

C#
var ninja = container.Resolve<Ninja>(typeof(SuperNinja).ToString());
ninja.Weapon.Use(); 

Apparently ninja used superNinja weapon, and it was already dangerous. We want the way of setting of a special injection only for SuperNinja class. And such is the way.

Protected Contextual Dependency Injection

We need to configure the container by addition of a new dependence:

C#
container.RegisterType<SuperNinja>(
    new InjectionProperty("SuperWeapon", new Shuriken()));

Here all is simple. Particularly for SuperNinja type, it is underlined that at an injection in SuperWeapon property, it'll receive Shuriken type. We start the program and we receive a result similar to the previous one. But here also, we expect a problem. Let's call one more SuperNinja and we'll ask him where he takes the weapon. To be exact, the question will sound like: “Listen, guy, you borrowed this SuperWeapon at your friend SuperNinja?”

We will express this question in code:

C#
class Program
{
    static void Main(string[] args)
    {
        var container = new UnityContainer();
        container.RegisterType<IWeapon, Sword>();

        container.RegisterType<SuperNinja>(
            new InjectionProperty("SuperWeapon", new Shuriken()));

        var ninja = container.Resolve<Ninja>();
        ninja.Weapon.Use();

        var superNinja = container.Resolve<SuperNinja>();
        superNinja.SuperWeapon.Use();

        var superNinja2 = container.Resolve<SuperNinja>();

        Console.WriteLine(
            ReferenceEquals(superNinja.SuperWeapon, superNinja2.SuperWeapon));

        Console.ReadKey();
    }
} 

And he will answer us:

Ninja_3.png

I.e. it turns out that he has all the same borrowed weapons as the friend. Speaking to the programming language, references on SuperWeapon the first and the second SuperNinja coincide. Well, in it there is nothing bad, such mutual aid between friends is complimented. But let's try to make it so that everyone ninja had the SuperWeapon. How? At first sight, we can be helped by the ResolvedParameter class. It is intended just for this purpose. Unique restriction which can stop us is that the given class generates object on the basis of the container of injections to which configuration is applied. As a consequence, for our IWeapon interface, it will find Sword again. The truth is that it is possible to try to use the second constructor of ResolvedParameter class, but it is required to transfer a dependence name.

The code will assume the following:

C#
class Program
{
    static void Main(string[] args)
    {
        var container = new UnityContainer();
        container.RegisterType<IWeapon, Sword>();
        container.RegisterType<IWeapon, Shuriken>(typeof(SuperNinja).ToString());

        container.RegisterType<SuperNinja>(
            new InjectionProperty(
                "SuperWeapon",
                new ResolvedParameter<IWeapon>(typeof(SuperNinja).ToString())));

        var ninja = container.Resolve<Ninja>();
        ninja.Weapon.Use();

        var superNinja = container.Resolve<SuperNinja>();
        superNinja.SuperWeapon.Use();

        var superNinja2 = container.Resolve<SuperNinja>();

        Console.WriteLine(
            ReferenceEquals(superNinja.SuperWeapon, superNinja2.SuperWeapon));

        Console.ReadKey();
    }
} 

Apparently from a source code, there is a named dependence again. But one of the old disadvantages, namely inconvenient creation of objects is already irrelevant.

We have reached our result:

Ninja_4.png

It was possible to stop, but our code still had a number of disadvantages. We will list them: the code is dependant with string name of property; Ninja class also has access to dependence of SuperNinja class (a consequence from the second disadvantage of the named dependence). We will try to eliminate these disadvantages by the introduction of an additional level of abstraction.

C#
public static class UnityContainerHelper
{
    private static IDictionary<Type, IUnityContainer> Container { get; set; }

    public static IUnityContainer RegisterType<TFrom, TTo, TFor>(
        this IUnityContainer container, 
        params InjectionMember[] injectionMembers)
        where TTo : TFrom
    {
        if (Container == null)
        {
            Container = new Dictionary<Type, IUnityContainer>();
        }

        var key = typeof(TFor);

        if (Container.ContainsKey(key) == false)
        {
            Container[key] = container.CreateChildContainer();
        }

        return Container[key].RegisterType<TFrom, TTo>();
    }

    public static T ResolveType<T>(this IUnityContainer container)
    {
        var key = typeof(T);
        return 
            Container.ContainsKey(key) ?
            Container[key].Resolve<T>() :
            container.Resolve<T>();
    }
}

We created a service class with a pair of extension methods. We will explain their work. The first method extends registration of dependences in IUnityContainer. At its using, it is required to set explicitly type for which dependence makes sense. The given type is a key in the dictionary of dependences, and value is the container which redefines parent dependence. The second method extends a method of the resolving of dependences. If the object type for which there is an injection is available in the dictionary, the redefined dependence is applied. Otherwise, dependence resolves with help of parent container. It is necessary to notice that the code supports only one parent container. It has been made specially, because I don't overload a program code of unnecessary details. Implementation is easy for one more container and you'll think it up yourself.

The program code became simpler:

C#
class Program
{
    static void Main(string[] args)
    {
        var container = new UnityContainer();
        container.RegisterType<IWeapon, Sword>();
        container.RegisterType<IWeapon, Shuriken, SuperNinja>();

        var ninja = container.ResolveType<Ninja>();
        ninja.Weapon.Use();

        var superNinja = container.ResolveType<SuperNinja>();
        superNinja.SuperWeapon.Use();

        var superNinja2 = container.ResolveType<SuperNinja>();

        Console.WriteLine(
            ReferenceEquals(superNinja.SuperWeapon, superNinja2.SuperWeapon));

        Console.ReadKey();
    }
}

Note that instead of Resolve method, we use our extending ResolveType method. In the rest, the code is transparent enough.

Conclusion

I hope that I have answered questions to Giorgio Bozio and my readers. Comments are welcome.

Thank you, Oleg Smirnov.

License

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


Written By
Russian Federation Russian Federation
Software architect.

Comments and Discussions

 
GeneralContextual Dependency Injection is useful Pin
GWSyZyGy16-Dec-08 6:34
GWSyZyGy16-Dec-08 6:34 
GeneralService locator [modified] Pin
Giorgio Bozio2-Dec-08 10:56
Giorgio Bozio2-Dec-08 10:56 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.