Depuis l’émergence du mouvement Craft, le Clean Code et les principes SOLID sont à la mode. Tout développeur qui se respecte doit produire du code maintenable, testable et réutilisable. Dans cet article, nous allons vous présenter Ninject, un outil dont le but est de faciliter la production d’un tel code.

Dans le premier article sur Ninject, nous avons vu comment gérer les dépendances. Maintenant, nous allons voir comment gérer la durée de vie des objets.

Durée de vie des objets instanciés avec Ninject

Ninject permet de contrôler de manière très précise la durée de vie – appelée scope – des objets qu’il instancie. On peut lui demander un Singleton, un objet transient, un objet ayant la durée de vie d’un thread, d’une requête …

Singleton

Au Binding, on a la possibilité de spécifier qu’une classe est un singleton ou pas. Vous n’avez pas besoin de vous en préoccuper au moment où vous programmez si votre classe est singleton ou pas. C’est le moteur de Ninject qui va faire le reste.
Lorsque vous aller faire le binding de votre classe, vous pouvez spécifier un mode singleton :

var kernel = new StandardKernel();
 
kernel.Bind<Logger>().ToSelf().InSingletonScope();

Ainsi chaque injection de l’objet Logger se fera avec la même instance. Vous évitez d’utiliser des variables statiques et des locks pour créer votre singleton. Cela vous permet d’utiliser l’injection de dépendance. Vous pourrez lors de vos tests unitaires injecter un objet de substitution.

Ninject nous permet également de définir des singletons suivant certains contextes. L’un d’entre eux est le thread context.

Scope de Thread

var kernel = new StandardKernel();
 
kernel.Bind<Logger>().ToSelf().InThreadScope();

Cela aura pour effet de spécifier que chaque injection de l’objet Logger contiendra la même instance tant que vous êtes sur un thread donné. Un thread = une instance de classe. Cela peut permettre d’éviter des problèmes d’accès simultanés, que l’on peut avoir avec un singleton.

Scope de Requête

Dans le cas d’une application ASP.Net MVC, il peut être intéressent d’initialiser une classe pendant toute la durée du contexte http. C’est assez similaire au contexte d’un thread :

private static void RegisterServices(IKernel kernel)
{
    kernel.Bind<Logger>().ToSelf().InRequestScope();
}        

Pour pouvoir en profiter, il faut ajouter le package nuget Ninject.MVC5. Ce package ajoute la méthode d’extension « InRequestScope », ce qui vous assure que l’instance du logger ne sera pas utilisée pour une autre requête http. Et cela vous permet toujours d’utiliser l’injection de dépendance. Vous pouvez, par exemple, injecter votre contexte de base de données en mode InRequestScope. Cela vous assure d’ouvrir et fermer la connexion à la base de données une seule fois pour chaque demande de page web.
Dans le cas où ces différents contextes ne suffisent pas, on peut créer son propre scope avec la méthode « InScope ».

object obj = new object();
kernel.Bind<Logger>().ToSelf().InScope(ctx => obj);

La méthode prend une lambda qui sera interprétée pour déduire l’instance à utiliser au moment de l’injection. Ainsi, dans l’exemple, on vient de ré-implémenter un singleton car à chaque fois que l’on va évaluer la lambda la même valeur de object sera renvoyée.

La suite dans un prochain article…