Click here to Skip to main content
5,785,816 members and growing! (19,410 online)
Email Password   helpLost your password?
Development Lifecycle » Design and Architecture » Design and Strategy     Advanced License: The Code Project Open License (CPOL)

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

By O1eg Smirnov

Article describes how get contextual dependency injection in application using Unity Application Block
C#, Windows, Visual Studio, Architect, Dev

Posted: 30 Nov 2008
Updated: 30 Nov 2008
Views: 1,920
Bookmarked: 14 times
Note: This is an unedited reader contribution
Announcements
Loading...



Search    
Advanced Search
Sitemap
8 votes for this Article.
Popularity: 3.78 Rating: 4.19 out of 5
0 votes, 0.0%
1
0 votes, 0.0%
2
1 vote, 12.5%
3
4 votes, 50.0%
4
3 votes, 37.5%
5
Note: This is an unedited contribution. If this article is inappropriate, needs attention or copies someone else's work without reference then please Report This Article

Introduction

To write this article I was pushed conversation with one of the Italian software architects, namely with Giorgio Bozio. Idea with ninja is him. The topic for discussion was the question of how to use NInject for implementation Dependency Injection (DI) depending on the context. Now I suggest the 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 following classes and interfaces:

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

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

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

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

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

I'll give some comments to 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 are 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 framework which I used.

The code looks as follows:

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 which there will be an interface substitution by real objects implementing it.

The code output will be such:

Ninja_1.png

Let's explain result. Ninja and superNinja used the weapon and it had appeared Sword. As followed expect, 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:

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. A name it is possible to choose any, but we will choose it with sense - typeof(SuperNinja).ToString(), i.e. dependence for SuperNinja. The code has a little exchanged in place DI, we don't use a default injection, but use an injection with a certain name. It coincides that has been specified in new dependence.

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

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

That result which we also achieved:

Ninja_2.png

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

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 a code it is visible that the nested container redefines dependence of the parent container.

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

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

We can make so, for example:

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

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

Protected Contextual Dependency Injection 

We need cofigurate the container by addition of new dependence:

 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 result similar to the previous. But also here we are expected by 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 so: “Listen, guy, you borrowed this SuperWeapon at your friend SuperNinja?”

We will express this question in code:

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 the weapon at 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 make so that everyone ninja had the SuperWeapon. How? At first sight we can be helped by ResolvedParameter class. It is intended just for this purpose. Unique restriction which can stop us, it is that the given class generates object on the basis of the container of injections to which configuration it is applied. As consequence, for our IWeapon interface, it will be again found Sword. The truth 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:

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 old disadvantage, 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 depended 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 introduction of additional level abstraction.

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 pair 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 support 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 containers and you'll think up yourself.

The program code became simpler:

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 Giorgio Bozio and my readers. Welcome to comments.

Thank you, Oleg Smirnov.

License

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

About the Author

O1eg Smirnov


Software architect.
Location: Russian Federation Russian Federation

Article Top
Sign Up to vote for this article
You must Sign In to use this message board.
FAQ FAQ Noise ToleranceSearch Search Messages 
 Layout  Per page   
 Msgs 1 to 2 of 2 (Total in Forum: 2) (Refresh)FirstPrevNext
GeneralContextual Dependency Injection is usefulmemberGWSyZyGy7:34 16 Dec '08  
GeneralService locator [modified]memberGiorgio Bozio11:56 2 Dec '08  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 30 Nov 2008
Editor: Deeksha Shenoy
Copyright 2008 by O1eg Smirnov
Everything else Copyright © CodeProject, 1999-2009
Web17 | Advertise on the Code Project