Tuesday, February 17, 2009 11:56 PM Kazi Manzur Rashid

Use Bootstrapper in Your ASP.NET MVC Application and Reduce Code Smell

In this post, I will show how you can use a simple bootstrapper to make your application more extensible. In a typical ASP.NET MVC application you will find there are lots of thing going on in Application_Start, like configuring your IoC/DI, registering routes, model binders etc. The following is the code snippet of latest Oxite source:

protected virtual void OnStart()
{
    setupContiner();

    setupSite();

    registerRoutes();

    registerActionFilters();

    registerModelBinders();

    registerViewEngines();

    registerControllerFactory();

    launchBackgroundServices();
}

Don't you think there are too many things going on, Is there any way to extend it, how do you add new routes/model binder/view engine without modifying it, does not it violet the Open Closed Principle?

The Bootstrapper

The bootstrapper should have only one responsibility, execute the start up tasks, so first lets create a Task interface:

public interface IBootstrapperTask
{
    void Execute();
}

 

Next, create few small classes for each kind of task which implements this interface, I will use my previous blog post example in this case:

RegisterControllerFactory:

public class RegisterControllerFactory : IBootstrapperTask
{
    private readonly IControllerFactory _controllerFactory;

    public RegisterControllerFactory(IControllerFactory controllerFactory)
    {
        _controllerFactory = controllerFactory;
    }

    public void Execute()
    {
        ControllerBuilder.Current.SetControllerFactory(_controllerFactory);
    }
}

RegisterRoutes:

public class RegisterRoutes : IBootstrapperTask
{
    private readonly RouteCollection _routes;

    public RegisterRoutes() : this(RouteTable.Routes)
    {
    }

    public RegisterRoutes(RouteCollection routes)
    {
        _routes = routes;
    }

    public void Execute()
    {
        _routes.Clear();

        _routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
        _routes.MapRoute("Default", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = "" });
    }
}

As you can understand there can be more, for example, I am using it in DotNetShoutout for creating default users, running background tasks etc. Next create a static class Bootstrapper which will execute these tasks:

public static class Bootstrapper
{
    static Bootstrapper()
    {
        ConfigureContainer();
    }

    public static void Run()
    {
        var tasks = ServiceLocator.Current.GetAllInstances<IBootstrapperTask>();

        foreach(var task in tasks)
        {
            task.Execute();
        }
    }

    private static void ConfigureContainer()
    {
        IUnityContainer container = new UnityContainer();

        UnityConfigurationSection configuration = (UnityConfigurationSection) ConfigurationManager.GetSection("unity");
        configuration.Containers.Default.Configure(container);

        ServiceLocator.SetLocatorProvider(() => new UnityServiceLocator(container));
    }
}

And in the Global.asax:

protected void Application_Start()
{
    Bootstrapper.Run();
}

 

And in the web.config, we can wired the tasks like the following:

<unity>
    <typeAliases>
        <typeAlias alias="IControllerFactory" type="System.Web.Mvc.IControllerFactory, System.Web.Mvc"/>
        <typeAlias alias="ControllerFactory" type="UnityCommonServiceLocatorMVC.CommonServiceLocatorControllerFactory, UnityCommonServiceLocatorMVC"/>
        <typeAlias alias="IBootstrapperTask" type="UnityCommonServiceLocatorMVC.IBootstrapperTask, UnityCommonServiceLocatorMVC"/>
        <typeAlias alias="RegisterRoutes" type="UnityCommonServiceLocatorMVC.RegisterRoutes, UnityCommonServiceLocatorMVC"/>
        <typeAlias alias="RegisterControllerFactory" type="UnityCommonServiceLocatorMVC.RegisterControllerFactory, UnityCommonServiceLocatorMVC"/>
    </typeAliases>
    <containers>
        <container>
            <types>
                <type name="registerRoutes" type="IBootstrapperTask" mapTo="RegisterRoutes"/>
                <type type="IControllerFactory" mapTo="ControllerFactory"/>
                <type name="registerControllerFactory" type="IBootstrapperTask" mapTo="RegisterControllerFactory">
                    <typeConfig extensionType="Microsoft.Practices.Unity.Configuration.TypeInjectionElement, Microsoft.Practices.Unity.Configuration">
                        <constructor>
                            <param name="controllerFactory" parameterType="IControllerFactory">
                                <dependency/>
                            </param>
                        </constructor>
                    </typeConfig>
                </type>
            </types>
        </container>
    </containers>
</unity>

So by using this bootstrapper we are making our application completely extensible, we can create new task and execute it in the application start without modifying anything.

Comments/Suggestions?

Download: Complete Source

Shout it
Filed under: , , , , , , , ,

Comments

# re: Use Bootstrapper in Your ASP.NET MVC Application and Reduce Code Smell

Wednesday, February 18, 2009 4:20 AM by Andrew Davey

Hmm, I'm not sure it's "better". I'd probably call out YAGNI.

You have converted a set of nicely named methods into lots of classes, contructors, etc and a whole bunch of messy XML config. In this instance I do not see this added complexity providing much more power.

I can see your motivation however, so I'll keep this method in mind for the future... Thanks for sharing.

# re: Use Bootstrapper in Your ASP.NET MVC Application and Reduce Code Smell

Wednesday, February 18, 2009 8:50 AM by Seth Petry-Johnson

I agree with Andrew. The end result is certainly more extensible, but it's much harder to read and understand, especially at a glance.

This might be a good approach if you have a specific, important reason that you _need_ to configure startup tasks in configuration, rather than in code. Otherwise, I think the original startup method was perfect.

# re: Use Bootstrapper in Your ASP.NET MVC Application and Reduce Code Smell

Wednesday, February 18, 2009 9:28 AM by Kazi Manzur Rashid

Well Guys it just a matter of principle whether you would like to create a dump, tightly coupled system vs dynamic, loosely coupled.

>>>You have converted a set of nicely named methods into lots of classes, contructors, etc

Pls dont hesitate to add new classes. Maybe the this link might help:

c2.com/.../wiki

>>>whole bunch of messy XML config

You can use the programmatic version of those IoC/DI library if you do not like angle brackets.

# re: Use Bootstrapper in Your ASP.NET MVC Application and Reduce Code Smell

Wednesday, February 18, 2009 12:39 PM by Jim

I'd say this definitely violates the KISS principle.

# re: Use Bootstrapper in Your ASP.NET MVC Application and Reduce Code Smell

Wednesday, February 18, 2009 3:31 PM by Chad Myers

If you were using StructureMap, this would've been automatic and already implemented for you, negating the KISS and YAGNI arguments. :)

As far as visibility, it's always a balance.  If you don't need the extensibility, then the procedural list of methods is preferable. If you do need extensibility, then the automatic loading is preferable.

The visibility argument is now in play. Beat this problem with diagnostics. Have a way of dumping out everything that's loaded and how it's mapped.

Again, StructureMap has a way to dump the entire configuration / diagnostics solving this problem.

In short, a lot of this code is to overcome of deficiencies in Unity and with a more mature container, this wouldn't be a problem :)

# re: Use Bootstrapper in Your ASP.NET MVC Application and Reduce Code Smell

Thursday, February 19, 2009 3:15 PM by Kazi Manzur Rashid

@Chad: This is nothing about Unity vs StructureMap as I mentioned in my post that you can use any IoC/DI of your choice. Yes I know SM is the oldest IoC/DI in .NET space and has some excellent features.

BTW I have changed the container configuration, now it uses Code rather than xml, download the source of this post weblogs.asp.net/.../100-unit-testable-linq-to-sql-repository.aspx

# re: Use Bootstrapper in Your ASP.NET MVC Application and Reduce Code Smell

Wednesday, February 25, 2009 9:28 AM by Todd Thomson

Try combining ASP.NET MVC and Prism2 (Logging and Modularity sections). You will need to make very few changes to the Prism2 code to get it to work with your MVC app. I'll post an article on my site soon.

# re: Use Bootstrapper in Your ASP.NET MVC Application and Reduce Code Smell

Thursday, February 26, 2009 6:22 AM by Kazi Manzur Rashid

@Todd: Yes I do have plan to bring some goodness from Prism. Keep an eye on my blog.