Ninject: Auto-registration is changing in version 3

When I was using Ninject v2.2 I had this code to do my auto-registration:

using Ninject;
using Ninject.Extensions.Conventions;

public class CommonBootstrapper<TShell>
{
    private StandardKernel _kernel;

    protected override void Configure()
    {
        _kernel = new StandardKernel();
        _kernel.Scan(scanner =>
                         {
                             scanner.FromAssembliesInPath(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));
                             scanner.BindWithDefaultConventions();
                             scanner.InSingletonScope();
                         });
    }
}

For various reasons I upgraded to Ninject v3.0 RC3, and I found that there have been a number of breaking in Ninject.Extensions.Conventions.  My code now looks like this:

using Ninject;
using Ninject.Extensions.Conventions;

public class CommonBootstrapper<TShell>
{
    private StandardKernel _kernel;

    protected override void Configure()
    {
        _kernel = new StandardKernel();
        _kernel.Bind(scanner => scanner.FromAssembliesInPath(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location))
                                    .Select(IsServiceType)
                                    .BindToDefaultInterface()
                                    .Configure(binding => binding.InSingletonScope()));
    }

    private static bool IsServiceType(Type type)
    {
        return type.IsClass && type.GetInterfaces().Any(intface => intface.Name == "I" + type.Name);
    }
}

 

So there is a sweet new fluent interface, but more importantly you have to specify the exact conventions to use.  This makes it a lot easier to have non-standard convention, but it would be great if Ninject had the standard convention built in (IFoo binds to Foo).

For those who are into their own custom binding conventions (like Anthony), you will unfortunately find that the IBindingGenerator interface has changed.  Here is the v2.2 way of implementing a custom binding:

public class ViewModelConventions : IBindingGenerator
{
    public void Process(Type type, Func<IContext, object> scopeCallback, IKernel kernel)
    {
        if(type != null && kernel != null && !type.IsAbstract && type.IsClass && type.Name.EndsWith("Model"))
        {
            kernel.Bind(type)
                  .ToSelf()
                  .InScope(scopeCallback);
        }
    }
}

And here is the same class ported to Ninject v3.0 RC3.

public class ViewModelConventions : IBindingGenerator
{
    public IEnumerable<IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(Type type, IBindingRoot bindingRoot)
    {
        if (type != null && !type.IsAbstract && type.IsClass && type.Name.EndsWith("Model"))
        {
            yield return bindingRoot.Bind(type)
                                    .ToSelf();
        }
    }
}

It must be said, however, the goodness of the new fluent interface shown above means that I no longer need a custom binding generator – instead I can simply select the types I want and bind them directly in my bootstrapper.   I suspect that others will find the same!

March 20 2012

Convention-based IOC is great … if everyone follows the conventions

Recently I started using Ninject for Inversion Of Control (IOC) and Dependency Injection (DI) on an ASP.Net MVC3 project.  Ninject is a very neat framework and is easy to use BTW and its offers some slick MVC3 integration through the Ninject.Web.Mvc project.

Being a proponent of convention-over-configuration, I also looked for some auto-registration code for Ninject and soon found the Ninject.Extensions.Conventions project.  The default convention here also suits me, since it binds IFooService to FooService in transient scope. Using the Scan extension method, I could now have the following code to initialise my IOC:

kernel.Scan(scanner =>
{
    scanner.FromAssemblyContaining<ProjectRepository>();
    scanner.BindWith<DefaultBindingGenerator>();
});

So far, so good, I thought, and now to apply IOC to my WCF services, which are hosted within the MVC web project (important point!).  Once again, Ninject has an answer, in the form of the Ninject.Extensions.Wcf project.  This project offers a custom ServiceHostFactory that will apply IOC to your service implementation simply by adding the Factory attribute in your .svc file:

<%@ ServiceHost Language="C#" 
                Debug="true" 
                Service="SharpFellows.ScrumToolkit.Web.Services.Authentication" 
                CodeBehind="Authentication.svc.cs" 
                Factory="Ninject.Extensions.Wcf.NinjectServiceHostFactory" %>

Very nice … except that it didn’t work (yet).  This didn’t surprise me much at this stage because both Ninject.Web.Mvc and Ninject.Extensions.Wcf define a custom HttpApplication class and both libraries expect you to derive from this in your global.asax.cs class.  I opted to keep the class for Mvc and patch in the functionality required by the class for Wcf.  [As an aside, this is only possible because of the nature of open source software – hurray for open source]  So here was my first attempt:

kernel.Scan(scanner =>
{
    scanner.FromAssemblyContaining<ProjectRepository>();
    // Ninject.Extensions.Wcf uses some binding internally
    scanner.FromAssemblyContaining<NinjectServiceHostFactory>();
    scanner.BindWith<DefaultBindingGenerator>();
});
// Ninject.Extensions.Wcf expects to find the kernel here
KernelContainer.Kernel = kernel;

Looking good … except that it still didn’t work.  Requests to the WCF service were now all met with this:

The service type provided could not be loaded as a service because it does not have a default (parameter-less) constructor. To fix the problem, add a default constructor to the type, or pass an instance of the type to the host.

After much head-scratching, it turns out that the IOC binding done internally by the Ninject.Extensions.Wcf project is to bind ServiceHost to NinjectServiceHost and this binding does not follow the default conventions laid down by Ninject.Extensions.Convention!  Obvious really, once you understand the conventions and look at the required binding.  So now the fix was pretty simple:

// Conventions pick up most of our IOC bindings  :-)
kernel.Scan(scanner =>
{
    scanner.FromAssemblyContaining<ProjectRepository>();
    scanner.BindWith<DefaultBindingGenerator>();
});

// This binding doesn't follow the convention  :-/
kernel.Bind<ServiceHost>().To<NinjectServiceHost>();

// Ninject.Extensions.Wcf expects to find the kernel here
KernelContainer.Kernel = kernel;

And now everything worked smoothly.  Smile

The moral of the story?  It is possible to get MVC controllers and WCF service classes controlled by the same Ninject kernel.  And if you use conventions, don’t assume that all libraries can and do use them!

June 2 2011

Dependency Injection in SharePoint with Ninject

 

A while ago I was having a discussion with one of my fellow developers at EMC Consulting about SharePoint and getting dependency injection working with it. Well finally after a few weeks I have found the time to produce a quick example of just how easy it is to get dependency injection working in SharePoint using a great tool called Ninject. You can find additional information about Ninject at http://ninject.org/. So this get started!
First off Ninject works by providing you with something it calls a kernel which it uses for returning an instance of a specific type. You can think about the kernel as a big brother to the factory pattern we all know and love. Because the kernel is so important the first things you need to do to get Ninject working in SharePoint is create an instance of a kernel and a simple way to do this in SharePoint is through the use of a HttpModule.

1:  public class SharePointNinjectHttpModule: IHttpModule, IDisposable
2:  {
3:         private readonly HttpApplication _httpApplication;
4: 
5:         public void Init(HttpApplication context)
6:         {
7:             if (context == null)
8:                 throw new ArgumentException("context");
9: 
10:             if(FrameworkHelper.Kernel == null)
11:             {
12:                 FrameworkHelper.Kernel = GetKernel();
13:             }
14:         }
15: 
16:         public void Dispose()
17:         {
18:             if(_httpApplication == null) return;
19:             _httpApplication.Dispose();
20:         }
21: 
22:         #region Private methods
23:         
24:         /// <summary>
25:         /// Gets the kernel.
26:         /// </summary>
27:         /// <returns></returns>
28:         private static IKernel GetKernel()
29:         {           
30:             IKernel result = new StandardKernel();
31:             result.Bind<IWarrior>().To<Samurai>();
32:             result.Bind<IWeapon>().To<Sword>();
33:             return result;
34:         }
35: 
36:         #endregion
37: }



As you can see from the code the module is very simple and straightforward and all it does is create an instance of the kernel and sets it's bindings so Ninject knows which instance of a type to return when a request for “IWarrior” or “IWeapon” is made. Remember that you will need to add an entry to the “httpModules” section of your web.config (see below) which in a real world application would be done using the SPWebConfigModification class. However, as this is just a demo I have added it by hand to save myself sometime.

1: <add name="SharePointNinjectHttpModule" type="Blog.IOC.Source.HttpModules.SharePointNinjectHttpModule,Blog.IOC, Version=1.0.0.0, Culture=neutral, PublicKeyToken=bf2ebb07a9bc44ba" />



Now to allow Ninject to actually do it's dependency injection magic there are a few things you must do. The first of these is to modify the “AssemblyInfo.cs” file for all of your projects (well the ones using Ninject at least) so they will allow partially trusted callers. If you don't do this then a security exception is thrown when you inject your object into the Ninject kernel.

1: using System.Security;
2: 
3: [assembly: AllowPartiallyTrustedCallers]



The next thing you need to do is inject the actual instance of the object you want Ninject to apply dependency injection to into the kernel you created. The way I did this was to create a number of base classes which inherit from commonly used items in SharePoint like Web Parts, User Controls and Application Pages. Then within the constructor for each base class I inject the instance of that object into the Ninject kernel.


This is the web part base class:

1: public abstract class WebPartBase : Microsoft.SharePoint.WebPartPages.WebPart
2: {
3:       protected WebPartBase()
4:       {
5:           FrameworkHelper.Kernel.Inject(this);
6:       }
7: }



This is the application page base class:

1: public class LayoutsBase : LayoutsPageBase
2: {
3:         protected LayoutsBase()
4:         {
5:             FrameworkHelper.Kernel.Inject(this);
6:         }
7: }



And finally the user control base class:

1: public abstract class UserControlBase : UserControl
2: {
3:         protected UserControlBase()
4:         {
5:             FrameworkHelper.Kernel.Inject(this);
6:         }
7: }



You can see all the bases classes shown below in the “Blog.IOC” project.

Blog.IOC.BaseClasses


Once you have done this Ninject will work and happily inject any dependencies you have marked up with the “[Inject]” attribute into your objects.

1: [Inject]
2: public IWarrior Warrior { get; set; }


So does this all work you ask? Well yes indeed it does and to prove it below is the code for a very simple application page which inherits off “LayoutsBase” and a screen shot of it’s rendered output.


[ Notice the use of the inject attribute on the Warrior property so Ninject knows this is something it is responsible for ]

1: public class BlogCustomApplicationPage : LayoutsBase
2: {
3:         protected Literal litWarrior;
4: 
5:         [Inject]
6:         public IWarrior Warrior { get; set; }
7: 
8:         protected override void OnLoad(EventArgs e)
9:         {
10:             base.OnLoad(e);
11: 
12:             SetUpWarrior();
13:         }
14: 
15:         private void SetUpWarrior()
16:         {
17:             litWarrior.Text = Warrior.Name;
18:         }
19: }



[ The fully rendered output ]
ApplicationPage


The full source code for the dependency injection example using Ninject can be download from: http://cid-468e9f9e14e99f80.skydrive.live.com/self.aspx/.Public/Blog.IOC.zip

PS. In order to get all this working you will need Visual Studio 2008, WSPBuilder and SharePoint 2007 enjoy :-)

April 20 2010
Older Posts