Tuesday, February 17, 2009 11:56 PM
kazimanzurrashid
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
Filed under: Asp.net, DotNetShoutout, ASPNETMVC, ASP.NET MVC, Common Service Locator, IoC/DI, Unity, ocp, Open Closed Principle