Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#4.0

Lazy Loading using Windsor Castle

3.40/5 (3 votes)
13 Feb 2014CPOL2 min read 18.4K  
Lazy loading object in DI using Castle Windsor & System.Lazy

Introduction

In this tip, I am going to show you how to instantiate object on demand using System.Lazy & Windsor Castle (DI Framework).

Background

In an application which I was working on, I came across an issue where developers have used lots of interfaces to instantiate a class from a single constructor. Application was been developed using Windsor DI framework. After doing some Googling, I came to know that this Windsor instantiates using constructor which has minimum number of parameters and we can’t control the constructor which needs to be instantiated. Here I see a problem. What if one of the instances goes down with some reason and this instance does have any role to play for completing the process.

Changing implementation at this point of time will be a big cost to pay. Other impact would be the Unit Test which has already been developed needs to changed.

Using the Code

Add a reference to Castle Windsor using Visual Studio Nuget. This will setup castle reference in your project. Include the following namespace in your class file.

C#
using Castle.MicroKernel.Resolvers;
using Castle.Windsor; 

For activating lazy loading in Windsor, you need to register interface ILazyComponentLoader with class LazyOfTComponentLoader.

C#
var container = new WindsorContainer();
           container.Register(
               Castle.MicroKernel.Registration.Component.For
              <ILazyComponentLoader>().ImplementedBy<LazyOfTComponentLoader>(),
               Castle.MicroKernel.Registration.Component.For
               <ITestA>().ImplementedBy<TestA>().LifestyleTransient(),
               Castle.MicroKernel.Registration.Component.For
               <ITestB>().ImplementedBy<TestB>().LifestyleTransient(),
               Castle.MicroKernel.Registration.Component.For
               <ITestLazyloading>().ImplementedBy<TestLazyloading>());

Now, the other change which you need to make with your class constructor is start taking this parameter via System.Lazy. You only need to make this change if you want your parameter to be Lazy loaded.

C#
public TestLazyloading(Lazy<ITestA> testA, Lazy<ITestB> testB) 

Now you will have to use LazyObject.Value to activate & access its attributes.

C#
AObject.Value.DoWork();

This will do the trick. Once you access .Value object would get instantiated.

Since you have made a change to your class constructor, you will also have to change your unit test. Making change to your unit test class would be simple. Create object of System.Lazy<T> and return the mock class which you were referring earlier.

C#
var lazyTestA = new Lazy<ITestA>(() => new TestA());

Set the object you have created in your class constructor for testing. That’s it. We are done with the changes we have to with our existing code.

You can find the below sample code using console application.

C#
class Program
    {
        static void Main(string[] args)
        {
            var container = new WindsorContainer();
            container.Register(
                Castle.MicroKernel.Registration.Component.For
                <ILazyComponentLoader>().ImplementedBy<LazyOfTComponentLoader>(),
                Castle.MicroKernel.Registration.Component.For
                <ITestA>().ImplementedBy<TestA>().LifestyleTransient(),
                Castle.MicroKernel.Registration.Component.For
                <ITestB>().ImplementedBy<TestB>().LifestyleTransient(),
                Castle.MicroKernel.Registration.Component.For
                <ITestLazyloading>().ImplementedBy<TestLazyloading>()
                );

            Console.WriteLine("Lazy loading execution Start");
            var test = container.Resolve<Lazy<ITestLazyloading>>();
            test.Value.TestingInstanceA();
            Console.WriteLine("Lazy loading execution complete");

            Console.ReadKey();

            Console.WriteLine("Executing Unit test case scenario start");
            var lazyTestA = new Lazy<ITestA>(() => new TestA());
            var lazyTestB = new Lazy<ITestB>(() => new TestB());

            var test2 = new TestLazyloading(lazyTestA, lazyTestB);
            test2.TestingInstanceA();
            test2.TestingInstanceB();

            Console.WriteLine("Executing Unit test case scenario end");

            Console.ReadKey();     
        }
    }

    public interface ITestA
    {
        void DoWork();
    }

    public interface ITestB
    {
        void DoMyWork();
    }

    public class TestA : ITestA
    {
        public TestA()
        {
            Console.WriteLine("Test A Activated");
        }

        public void DoWork()
        {

        }
    }

    public class TestB : ITestB
    {
        public TestB()
        {
            Console.WriteLine("Test B Activated");
        }

        public void DoMyWork()
        {

        }
    }

    public interface ITestLazyloading
    {
        void TestingInstanceA();
        void TestingInstanceB();
    }

    public class TestLazyloading : ITestLazyloading
    {
        private Lazy<ITestA> AObject = null;
        private Lazy<ITestB> BOject = null;

        public TestLazyloading(Lazy<ITestA> testA, Lazy<ITestB> testB)
        {
            AObject = testA;
            BOject = testB;
        }

        public void TestingInstanceA()
        {
            AObject.Value.DoWork();
            Console.WriteLine("A is been executed");
        }

        public void TestingInstanceB()
        {
            BOject.Value.DoMyWork();
            Console.WriteLine("B is been executed");
        }
    } 

Console Application Output

C#
Lazy loading execution Start
Test A Activated
A is been executed
Lazy loading execution complete
Executing Unit test case scenario start
Test A Activated
A is been executed
Test B Activated
B is been executed
Executing Unit test case scenario end 

License

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