Lazy loading using Ninject

In my previous blog post I demonstrated how you can use Ninject in your Silverlight application to automatically inject dependencies and make live easier. In the sample I injected the dependency, the PingService, inside my PageModel constructor. That worked just fine because the PingService is lightweight and stateless. However suppose creation is much more involved and you don’t need it all the time so you really want to divert creation until you really need the PingService. Well we can by just a few simple changes.


 


Changing the PageModel to defer loading of the PingService


This is actually a very easy change. All we need to do is change to constructor from expecting a PingService to expecting a IKernel. The IKernel is the Ninject main object and Ninject will take care of injecting itself. Kind of cool as the Page, which creates and uses the PageModel , doesn’t even need to be aware of the change, Ninject will do all the work here [:)].


Now we can change the ExecutePing() function to use the kernel to create the PingService when needed and we are done. The new PageModel looks like this:


using System;
using System.ComponentModel;
using System.Threading;
using Ninject.Core;
 
namespace NinjectSample
{
    public class PageModel : INotifyPropertyChanged
    {
        public PageModel(IKernel kernel)
        {
            _kernel = kernel;
            _context = SynchronizationContext.Current;
        }
 
        private IKernel _kernel;
        private SynchronizationContext _context;
        public DateTime TheResult { get; set; }
 
        public void ExecutePing()
        {
            PingService.PingService proxy = _kernel.Get<PingService.PingService>();
            proxy.BeginPing(proxy_PingCompleted, proxy);
        }
 
        void proxy_PingCompleted(IAsyncResult result)
        {
            PingService.PingService proxy = (PingService.PingService)result.AsyncState;
            _context.Post(state =>
                {
                    TheResult = proxy.EndPing(result);
 
                    if (PropertyChanged != null)
                        PropertyChanged(this, new PropertyChangedEventArgs("TheResult"));
                }, null);
        }
 
        public event PropertyChangedEventHandler PropertyChanged;
    }
}

The normal generated WCF PingService will work just fine as will the Page, no changes there. The only other change we need to make is to the TestPingService as this was a very simple implementation before. Not that it is very complicated now but it needs to work with a dummy IAsyncResult. The complete fake code looks like this:


using System;
 
namespace NinjectSample
{
    public class TestPingService : PingService.PingService
    {
        public IAsyncResult BeginPing(AsyncCallback callback, object asyncState)
        {
            TestAsyncResult result = new TestAsyncResult() { AsyncState = asyncState };
            callback(result);
            return result;
        }
 
        public DateTime EndPing(IAsyncResult result)
        {
            // Birthdate Charles Babbage
            return new DateTime(1791, 12, 26);
        }
    }
 
    class TestAsyncResult : IAsyncResult
    {
        public object AsyncState { get; set; }
        public System.Threading.WaitHandle AsyncWaitHandle { get; set; }
        public bool CompletedSynchronously { get; set; }
        public bool IsCompleted { get; set; }
    }
}

 


Easy right [:)]



Conclusion


Even though we are now using lazy loading instead of eager loading Ninject still makes live easy for us.


Enjoy!


Download source code

4 thoughts on “Lazy loading using Ninject

  1. Call me a nitpicker, but you’ve also coupled your PageModel to Ninject. ( I’m currently in the process of evaluating / deciding which IoC framework my company should use (finally…ugh) so keeping the contact surface between my code and the framework as small as possible is a big thing for me now)

    I would’ve implemented a LazyPingService wrapper that uses the kernel to create the real PingService on demand.
    This way the entire application will get the lazy version of the ping service, and you have also created a single location in your application (the module that contains the PingService configuration) where you can decide if PingService is lazy-loaded or not.
    The downside would be that you now have an extra wrapper class that you have to maintain, and that the users of PingService don’t get to decide if they want lazy loading or not. YMMV as they say…

  2. @Remco,

    There is nothing wrong with your approach, in fact its a common design when the PingService is a more heavyweight object.

    If I understand you correctly your LazyPingService is going to create the PingService using Ninject. So the LazyPingService would also need a reference to Ninject and you have exactly the same dependency.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>