Home | Blog | Screencasts | Projects
# Thursday, March 12, 2009

My last post described a really simple scenario where I used a HttpHandler to configure StructureMap, then I showed some code that is used to replace the ‘new’ operation used to create a new instance like: ObjectFactory.GetInstance<NumberPrinter>()

 

This might seem a little clunky because you need to remember to use the StructureMap ObjectFactory, not all programmers are created equal, so it might slip through the cracks. What would a framework look like if it embraced the concept of DI?

Well it turns out that the ASP.MVC framework was designed from the ground up (or a mile up as the case may be, it was started on a plane flight). To configure StructureMap with ASP.NET MVC, firstly it’s OK to modify the global.asax (since this isn’t a SharePoint solution):

 

        protected void Application_Start()
        {
           
            StructureMapConfiguration.AddRegistry(new DIRegistry());

            ControllerBuilder.Current.SetControllerFactory( typeof(StructureMapControllerFactory)   );

        }

Here we configure StructureMap with the same method as my last post by using the StructureMapConfiguration.AddRegistry method. The second line is more interesting, we tell the MVC framework that we want StructureMapControllerFactory to be the factory class that creates our controllers. So the code to this class looks like:

 

public class StructureMapControllerFactory : DefaultControllerFactory
   
{
        protected override IController GetControllerInstance(Type controllerType)
        {
            try
           
{
                return ObjectFactory.GetInstance(controllerType) as System.Web.Mvc.Controller;

            }
            catch (StructureMapException x)
            {
                System.Diagnostics.Debug.WriteLine(ObjectFactory.WhatDoIHave());
                throw;
            }
        }       
    }

 

That’s pretty cool, so what it means now is that we can create our controllers to take an instance of anything we want to inject. Continuing from the example with a simple Number interface:

 

public class TestController : Controller
{
        INumber _number;
        public TestController(INumber number)
        {
            _number = number;
        }

        public ActionResult Index()
        {
           
            return View(_number.GetNumber());
        }

}

 

This means that the controller has been passed an instance of INumber that has been created by StructureMap. Once you do the initial setup, it’s now pretty hard to make any mistakes in regards to not calling the proper Create methods.

Thursday, March 12, 2009 11:30:00 AM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
ASP.NET MVC | code | StructureMap

One of my favourite Dependency Injection (DI) containers is Jeremy Miller’s StructureMap, it’s full featured and light weight, but what I really like the most is the fluent configuration API which means we can write code like this:

ForRequestedType<INumber>()
                .TheDefaultIsConcreteType<Number>();

 

I also like that you don’t need to put custom attributes in your code.

 

It’s all pretty abstract so lets assume we have a simple interface, I’m deliberately keeping it simple:

   

public interface INumber
{
     int GetNumber();
}

 

A simple implementation of this interface:

 

public class Number : INumber
{      
        public int GetNumber()
        {
            return 999;
        }      
}

 

 

I’ve built a really simple (read: don’t use this in anything other than an experiment, the DI container in SharePoint gets configured for every request, including for images and scripts). This handler calls StructureMapConfiguration.AddRegistry with a class that derives from Registry which contains our fluent configuration information.

 

Why have I implemented this as a HTTPHandler?

If you read the Guidance on How to enable Unity in a SharePoint Application (unity is Microsoft’s DI container), the first step is to modify the Global.asax file. I have a problem with doing this for the simple reason that your touching the SharePoint system files, any upgrade will likely cause problems. It really is a shame that you can’t access the application onstart event using another mechanism.

I most certainly agree that the application onstart event is the perfect place to setup your DI container and if your happy to modify and deploy your changes to a global.asax file then go right ahead, put the code below into this file.

 

So it got me thinking, would a DI container like StructureMap work if it was setup in the begin request method of a HttpHandler? so my test code is:

 

namespace DIHttpModule
{
    public class DIHttpModule : IHttpModule
   
{  
        public void Dispose()
        {
          
        }

        public void Init(HttpApplication context)
        {
            context.BeginRequest += new EventHandler(context_BeginRequest);
        }

        void context_BeginRequest(object sender, EventArgs e)
        {
            StructureMapConfiguration.AddRegistry(new DIServiceRegistry());

            INumber numberGen = ObjectFactory.GetInstance<INumber>();

            ((HttpApplication)sender).Response.Write("Number: " + numberGen.GetNumber().ToString());
        }      
    }

    public class DIServiceRegistry : Registry
   
{
        protected override void configure()
        {
            ForRequestedType<INumber>()
                .TheDefaultIsConcreteType<Number>();
        }
    }
}

 

So after I deploy and configure my HttpHandler I do in fact see the number ‘999’ display at the top of each page (it also breaks JavaScript etc. because it writes this value into every request)

What has happened is that the call ObjectFactory.GetInstance<INumber>() has created an instance of Number(), we didn’t have to explicitly new up a Number() object.

That is a pretty basic example, lets expand it a little:

 

public class NumberPrinter
{
        private INumber _number;

        public NumberPrinter(INumber number)
        {
            _number = number;
        }

        public string PrintNumber()
        {
            return _number.GetNumber().ToString();
        }
}

 

Notice the constructor, it takes an INumber interface, the constructor is special as far as StructureMap is concerned, if StructureMap is asked to create an instance of NumberPrinter it will see that the constructor takes an INumber parameter and will attempt to pass in an instance of that type.

 

So assuming we changed the HttpModule to the following code:

 

NumberPrinter printer = ObjectFactory.GetInstance<NumberPrinter>();
((HttpApplication)sender).Response.Write(" Number : " + printer.PrintNumber());

 

We can see that again our output is ‘999’, StuctureMap was smart enough to create an Instance of INumber and pass it in, if you think about it, that’s pretty cool. It means that you can replace any concrete Instance of INumber with a single configuration change, that is powerful when we want to test our object in isolation, which is a whole other topic.

 

That’s a pretty trivial example, we did the StructureMap configuration and called ObjectFactory.GetInstance in the same method, now lets try it out in a web part which will be invoked later in the page life cycle (also remove the response.write from the HttpModule):

 

public class NumberWebPart : System.Web.UI.WebControls.WebParts.WebPart
{
        protected override void RenderContents(System.Web.UI.HtmlTextWriter writer)
        {
            NumberPrinter printer = ObjectFactory.GetInstance<NumberPrinter>();
            writer.Write("Web Part: " + printer.PrintNumber());
        }
}

 

Running this web part gives the expected result:

 

image

 

Again this is a really trivial example, that’s the point, you can clearly see that we are using a DI tool called StructureMap to create instances of our objects. Sure you could do away with the HttpHandler and move the configuration into the web.config file. But I do think the HttpHandler method warrants more thought however, because its useful when you introduce NHibernate to the mix, which is another framework that needs to do some expensive start up, which is also suited to the global.asax methods, but it does have some characteristics that should be managed per request, but that’s another post.

 

For now, hopefully I’ve proved some thought around DI and how can we manage the SharePoint deployments that really yell out for Application OnStart events without modifying the system file.

 

 

Thursday, March 12, 2009 9:10:00 AM (E. Australia Standard Time, UTC+10:00)  #    Comments [0] - Trackback
code | Sharepoint | StructureMap
Statistics
Total Posts: 191
This Year: 4
This Month: 0
This Week: 0
Comments: 41