Skip to main content

Dependency Injection in SharePoint Featuring 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 :-)

Comments

Popular posts from this blog

X509 certificate encryption fun :-)

Recently I needed to encrypt data on a server and allow a limited number of service accounts the ability to decrypt that data so it was as safe as possible. The approach I took to achieve this was by using a X509 certificate and it's ability to allow you to encrypt information via it's public key and decrypt that information through the private key. The key parts of this approach are: - Create a certificate - Ensure the KeySpec of the certificate is set up correctly to allow for encryption e.g. "KeyExchange" or "None" if you are doing this via PowerShell - Set the security on the private keys so only specific user accounts can access it and decrypt information encrypted via the public key. Step 1 - Create a certificate to use The easiest way to get a quick example going is via PowerShell to create a dummy root certificate and the one we will use for encrypting and decrypting. $rootCert = New-SelfSignedCertificate -CertStoreLocation Cert:\LocalMachine\My -Dns

SharePoint - Search Service Application (SSA) - Attempted to perform an unauthorized operation

On my current project I needed to adjust and add some search mapping via SharePoint's Central Administration web site. This should have been very straight forward as you have the ability to add managed properties and mappings easily via the UI. However, when I went to save my changes I got the error "The settings could not be saved because of an internal error: Attempted to perform an unauthorized operation". Now this was very confusing as I am administrator on the server and added into all of the correct SharePoint groups. I also tried the same action via PowerShell and got the same error.   After a few hours of research and head scratching I managed to get to the bottom of the problem which is the way my user account had been added as an administrator to the server. In the company I work for to make it easier to manage the administrators on a server a group is created in active directory called " servername_admins ". This group is added to the local administra

Why poor tests are worse than no tests

It's been awhile since I wrote my last blog post so I thought I would resume with a subject close to my heart...unit testing. Unit testing is tricky and lots of people don't focus enough on the key pillars that make up a good test: Trustworthy - Can the test be run multiple times and work in the same way each time? A test which works sometimes and fails randomly when a build happens during continuous integration(CI) is just going to be ignored and has no benefit to the team. Worse still, a bad test can give you a false impression that everything is fine when really it's not.   Readable - Can you look at the name of the test and work out what it's meant to do? For example, a test named "It_works_and_doesnt_fail" isn't as good as "It_will_add_a_valid_order_without_errors". Maintainable - Is your test simple to setup and refactor when code changes are made in the rest of the system? The