Ninject Mini Tutorial – Part 2

Go to Part 1

 

Controlling the Life Cycle of your Objects

In the previous post we did not concern ourselves with the lifecycle of the object returned from Ninject kernel. Ninject provides the following 4 built-in lifecycles (scopes):

  1. Transient (default)
  2. Singleton (only one instance)
  3. Thread (one instance per thread)
  4. Request (one instance per web request).

You can create custom scopes if needed.

Singleton:

using (IKernel kernel = new StandardKernel())
{
    kernel.Bind<ITaxCalculator>()
        .To<TaxCalculator>()
        .InSingletonScope()
        .WithConstructorArgument("rate", .2M);

    var tc1 = kernel.Get<ITaxCalculator>();
    var tc2 = kernel.Get<ITaxCalculator>();

    Assert.Same(tc1, tc2);
}

Transient:

using (IKernel kernel = new StandardKernel())
{
    kernel.Bind<ITaxCalculator>()
        .To<TaxCalculator>()
        .InTransientScope() 
        .WithConstructorArgument("rate", .2M);

        var tc1 = kernel.Get<ITaxCalculator>();
        var tc2 = kernel.Get<ITaxCalculator>();

        Assert.NotSame(tc1, tc2);
}

More Details on Injection Patterns

With Ninject you can inject:

  1. Constructor parameters
  2. Properties
  3. Methods

Before considering each one in turn, we just need to introduce the [Inject] attribute which may be used to tag constructors, properties and methods requiring injection. Obviously, by tagging constructors, properties or methods, your objects cease to be POCOs.

Constructor Injection

We have already seen an example of constructor injection in Part I when the kernel auto-magically injected an implementation of ITaxCalculator to the Sale Area constructor. In that case, even if we didn't tag the constructor with the [Inject] attribute, the kernel was able to perform the required binding. How?

That was actually a special case: when there is only one constructor available, the tagging is not needed. On the other hand, if there's more than one constructor defined, then then kernel can inject a dependency to only one constructor that needs to have the [Inject] attribute:

public class Sale3
{
    private readonly ITaxCalculator taxCalculator;

    public Sale3() { }

    [Inject]
    public Sale3(ITaxCalculator taxCalculator)
    {
        this.taxCalculator = taxCalculator;
    }

    // other stuff
}

Properties Injection

Instead of passing in the dependencies through the constructor, you can also inject them as properties. Injecting properties is pretty straightforward:

public class Sale2 
{ 
    [Inject] 
    public ITaxCalculator TaxCalculator { get; set; } 
    
    // implicit default constructor and other stuff... 

    public decimal GetTotal() 
    { 
        decimal total = 0M; 
        foreach (var item in lineItems) 
        { 
            total += TaxCalculator.CalculateTax(item.TotalPrice) 
                    + item.TotalPrice; 
        } 
        
        return total; 
    } 
}

Usage (note that we never explicitely set the TaxCalculator):

using (IKernel kernel = new StandardKernel())
{
    kernel.Bind<ITaxCalculator>()
                  .To<TaxcCalculator>()
                  .WithConstructorArgument("rate", .2M);

    var lineItem1 = new SaleLineItem("Gone with the wind", 10M, 1);
    var lineItem2 = new SaleLineItem("Casablanca", 5M, 2);

    var sale = kernel.Get<Sale2>(); // property injection!
    sale.AddItem(lineItem1);
    sale.AddItem(lineItem2);

    Assert.Equal(24M, sale.GetTotal());
}

There's an important caveat: if you have 2 or more properties injected, the order in which each dependency is injected is not predictable. This might complicate your design, if those dependencies are coupled somehow (e.g. dependency A needs dependency B). For this kind of situations, constructor or method injection is usually preferred.

Methods Injection

Finally, it’s also possible to tag methods for injection. As with constructor parameters, it’s possible to inject more than one value at once.

public class Sale4
{
    private ITaxCalculator taxCalculator;

    // other stuff

    // method injection, will be called by the kernel
    [Inject]
    public void SetTaxCalculator(ITaxCalculator taxCalculator)
    {
        this.taxCalculator = taxCalculator;
    }

    public decimal GetTotal()
    {
        decimal total = 0M;
        foreach (var item in lineItems)
        {
            total += taxCalculator.CalculateTax(item.TotalPrice) 
                  + item.TotalPrice;
        }

        return total;
    }
}

Usage (note that we never explicitely call the SetTaxCalculator):

using (IKernel kernel = new StandardKernel())
{
    kernel.Bind<ITaxCalculator>()
          .To<TaxCalculator>()
          .WithConstructorArgument("rate", .2M);

    var lineItem1 = new SaleLineItem("Gone with the wind", 10M, 1);
    var lineItem2 = new SaleLineItem("Casablanca", 5M, 2);

    var sale = kernel.Get<Sale4>(); // method injection!
    sale.AddItem(lineItem1);
    sale.AddItem(lineItem2);

    Assert.Equal(24M, sale.GetTotal());
}

Go to Part 1

kick it on DotNetKicks.com

This entry was posted in .NET, C#, Design and Patterns and tagged , , , , . Bookmark the permalink.
  • http://pulse.yahoo.com/_ZJ2U3SC6CEYGNWSQQJCOD76FIY sam

    You are awesome. Thanks for sharing this in its simplest form.

  • http://pulse.yahoo.com/_3X3UMSKFPT2OUXLJIY4DZDG75E Joe

    Too bad your download source code doesn;t work and is missing files.

  • Anonymous

    @Joe, thank you for pointing that out. For some reason my repo was corrupted on Github. It should have been fixed now, let me know if you still experience any problem.
    @yahoo-3X3UMSKFPT2OUXLJIY4DZDG75E:disqus
    Stefano

  • Poobalan

    Clear explanation… 

  • Anonymous

    Poobalan, glad you’ve found this useful.

  • Anonymous

    @b868b8d535084bd041ddf60ea3d2d9ab:disqus, glad you’ve found it useful.

  • nate

    Like the tool for quick n unit testing code, not too fond on the attribute designations and thus loosing POCO, personally I feel more comfortable inquring for a common domain interface and using a simple factory class to call a SetTaxCalculator method directly (if the SetTaxCalculator method is part of a public interface defintion) versus using attributes on third party classes (even open source and community ones). The attributes being actual class implementations versus calling a SetTaxCalculator based on a abstract pattern assuming SetTaxCalculator is part of an interface. Even so I like this tool for the quick implemenation unit testing and later refactoring out as more testing generic factory patterns setting the dependencystrategy are developed.

  • Anonymous

    Nate, I see understand your point. 

    However, marking your POCOs with Ninject attributes is not strictly required. See the example in my previous post (Part I).

  • Durga Venkateswararao

    Great Article, can i have suggestions like this on moq…

  • Davidylam

    Where is the source code?

  • Anonymous

    You can download the sample code from Github: https://github.com/stefanoric/NINJECTTUTORIAL

  • http://twitter.com/cat_vominh VO Minh Cat

    It was very useful for newbie like me to deep in IoC, behind the theory

  • kmoha

    well crafted

  • Sachin Gupta

    Thank you for sharing, It clear some doubts of mine.

  • Daniel Marbach

    Hy
    Even with multiple ctors you dont need the attribute. Ninject will take the one with the most parameters matching internal binding metadata. Ctor selection is pretty sophisticated.

    Daniel

  • Chan Souvannarath

    Stefano,
    Nice tutorial, great introduction to Dependency Injection using Ninject.
    Chan Souvannarath

  • stefanoricciardi

    @e0ce4b129143918e50dce15b3081cdb3:disqus,
    glad you’ve find it useful!

  • Artiom K.

    Thank you Stefan for your work, it helped me to understand how it works quickly. Thank you.

  • stefanoricciardi

    Glad it helped!

  • http://twitter.com/dytes DOU YuTao

    Thanks for sharing, very useful.

  • Ravi Kiran Karanam

    simple presentation easy to understand. cool !

  • A Shrikhande

    Great tutorial. thank you.

  • FS

    Thx alot for method IsSingleton!

  • Frédérick Roy

    Great article – Thk

  • Del

    Thanks for the tutorial, well explained. I have some projects in .Net 2 that i want to use Ninject 1.5 in but it seems like implementation is quite different. Do you have any samples or know where i can get for 1.5? Thanks much.

  • stefanoricciardi

    Del,

    unfortunately I cannot help you with that. Sorry!

    Stefano R.

  • Pingback: Ninject – Dependency Injection | Akin Family Blog