Home - About me - Browse by categories

[ASP.NET MVC] Bonnes pratiques : création d’un Bootstrapper ou comment isoler l’initialisation d’une application

Dans ce post, je souhaite revenir sur une bonne pratique que Rui et moi-même avons évoqué lors de notre session sur Rui le mois dernier : l’isolation de l’initialisation d’une application ASP.NET MVC.

En effet, le template par défaut de création de projet ASP.NET MVC de Visual Studio concentre tout le code dans un seul et même projet ce qui peut poser des problèmes de maintenabilité et/ou d’organisation, notamment sur un projet conséquent.

L’idée est de créer un Bootstrapper, c’est à dire une entité qui soit capable d’initialiser l’application, charger les différentes dépendances via un conteneur IoC (Unity, dans cet exemple), enregistrer les différentes routes, areas (etc…) qui composent l’application.

Voilà l’architecture globale de ma solution d’exemple (sources disponibles en bas de page!) :

image

Vous l’avez surement compris, l’essentiel du travail va se concentrer dans le projet Sample.Bootstrapper.

En premier lieu, le UnityBootstrapper : il s’agit d’une classe qui expose un conteneur Unity au reste de l’application, c’est celui-ci qui est utilisé pour la résolution des dépendances au runtime :

public class UnityBootstrapper
{
private UnityBootstrapper()
{

}

private static void InitializeContainer(IUnityContainer container)
{
container.RegisterType<ISampleService, LoremIpsumSampleService>();
}

private static readonly object _syncRoot = new object();
private static IUnityContainer _container;

public static IUnityContainer Container
{
get
{
if (_container == null)
{
lock (_syncRoot)
{
if (_container == null)
{
_container = new UnityContainer();
InitializeContainer(_container);
}
}
}

return _container;
}
}
}

On expose ici le conteneur Unity racine de l’application sous la forme d’un Singleton. Les registers sont fait dans le code ou dans le fichier Web.config, selon le besoin.

Afin de pouvoir utiliser l’injection de dépendance dans l’application, il faut configurer le moteur MVC pour utiliser ce conteneur Unity lors de la résolution des contrôleur. Pour cela, on passe par une implémentation de l’interface IControllerActivator, ici la classe UnityControllerActivator :

public class UnityControllerActivator : IControllerActivator
{
private readonly IUnityContainer _container;
public UnityControllerActivator(IUnityContainer unityContainer)
{
_container = unityContainer;
}

public IController Create(System.Web.Routing.RequestContext requestContext, Type controllerType)
{
return _container.Resolve(controllerType) as IController;
}
}

Il ne reste plus qu’à définir la bonne controller factory afin que le UnityControllerActivator soit utilisé.

Avant cela, j’attire votre attention sur la dernière classe qui se trouve dans le projet Sample.Bootstrapper : MvcApplication. Il s’agit en réalité de la classe d’application (qui dérive de System.Web.HttpApplication) et qui se trouve par défaut liée au fichier Global.asax, lors de la création du projet. Le fait de déporter cette classe dans un projet externe permet de bien isoler le chargement de l’application et d’y définir les différentes routes, areas ou comportement du Framework, par exemple, demander au ControllerBuilder d’aller utiliser notre propre IControllerActivator :

public class MvcApplication : HttpApplication
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}

public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

routes.MapRoute(
"Default",
"{controller}/{action}",
new { controller = "Sample", action = "Index" }
);

}

protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();

RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);

var controllerFactory = new DefaultControllerFactory(
new UnityControllerActivator(UnityBootstrapper.Container));
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
}
}

Il ne reste plus qu’à lier cette classe au fichier Global.asax afin qu’elle soit prise en compte au démarrage de l’application. Pour cela, il suffit d’ouvrir le fichier à l’aide de l’éditeur XML de Visual Studio, et de modifier la définition de la classe d’application :

<%@ Application Codebehind="Global.asax.cs" Inherits="Sample.Bootstrapper.MvcApplication" Language="C#" %>

Et voilà, le tour est joué! Les sources sont disponibles ici : http://juliencorioland.blob.core.windows.net/publicfiles/Sample-Bootstrapper.zip

A bientôt image

Julien


Any question about this post? Feel free to drop a comment below or contact me on Twitter @jcorioland