Bootstrapping your .NET MVC apps with executable tasks

When working on large projects in ASP.NET MVC I often try to automate the development workflow as much as possible. One of such automation points is the
bootstrapping logic required to fire up a typical MVC app. I'm referring to the following tasks:

  • Registering bundles.
  • Registering global filters.
  • Registering routes.
  • Registering areas.

I always find that this list easily blows up as the number of components grows. One great way to automate the registration of components at start-up is by using the Command pattern.

We'll start by creating the bootstrapper task interface.

public interface IBootstrapperTask  
{
    void Run();
}

The next step is to convert all config code located in App_Start to tasks. Here is an example of the bundle registrations.

public class RegisterBundles : IBootstrapperTask  
{
    public void Run()
    {
        var bundles = BundleTable.Bundles;

        bundles.Add(
            new ScriptBundle("~/assets/js/app").Include(
                "~/assets/some/kinda/js/script.js"));
    }
}

Now we just need to execute all bootstrapper tasks. This can be done using assembly scanning and reflection in Global.asax.

Assembly.GetExecutingAssembly()  
        .GetTypes()
        .Where(task => typeof (IBootstrapperTask).IsAssignableFrom(task))
        .ToList()
        .ForEach(task => task.Run());

And this is all it takes! But let's not stop here. In more complicated cases your bootstrapper tasks could have dependencies in the constructor. We can solve this using dependency injection.

I will show how to handle this using Autofac. You can do a similar thing with any other dependency injection container of your choosing. Let's scan the assembly and register all IBootstrapperTask implementations with the Autofac container.

public static void RegisterTasks(Assembly assembly)  
{
    Builder.RegisterAssemblyTypes(assembly)
           .Where(task => typeof (IBootstrapperTask).IsAssignableFrom(task))
           .As<IBootstrapperTask>()
           .SingleInstance();
}

You can call this from Global.asax or wherever you have your start-up code.

RegisterTasks(Assembly.GetExecutingAssembly());  

Once the Autofac container is built, all tasks can execute.

container.Resolve<IEnumerable<IBootstrapperTask>>()  
         .ToList()
         .ForEach(task => task.Run());

Now you can just drop new bootstrapper tasks in your App_Start (or wherever) and they will be executed automatically on start-up.