Comment empêcher Unity d’écraser des mappages existants avec AutoRegistration

Unity 3 offre de nouvelles fonctionnalités d’enregistrement automatique (enregistrement par convention) telles que:

container.RegisterTypes( AllClasses.FromLoadedAssemblies(), //uses reflection WithMappings.FromMatchingInterface, //Matches Interfaces to implementations by name WithName.Default); 

Ce code enregistrera tous les types qui implémentent leurs interfaces portant le même nom, par rapport à ces interfaces. Par exemple, la classe MyService: IMyService sera automatiquement enregistrée comme si vous aviez écrit ce qui suit:

 container.RegisterType(); 

Ma question: que se passe-t-il si je le souhaite la plupart du temps, mais que je souhaite choisir une implémentation différente pour l’une de mes interfaces, même s’il existe une implémentation de même nom?

Voir: Modèles et pratiques sur CodePlex

Un article important à lire expliquant pourquoi vous voudriez faire cela est l’ article de Convention sur la configuration de Jeremy Miller

Qu’est-ce qui vous empêche de remplacer le mappage automatique par un jeu personnalisé chargé depuis la configuration (ce qui signifie que, s’il est vide, aucun mappage par défaut n’est remplacé):

  // have your auto registration container.RegisterTypes( AllClasses.FromLoadedAssemblies(), //uses reflection WithMappings.FromMatchingInterface, //Matches Interfaces to implementations by name WithName.Default); // and override it when necessary container.LoadConfiguration(); 

où est la configuration

       

ou

    ...nothing, do not override defaults ...   

Le déplacement de la configuration facultative vers un fichier XML présente l’avantage: vous pouvez reconfigurer le système sans avoir à le recomstackr.

Unity a toujours utilisé une règle de “dernier gain” pour la configuration. Donc, faites d’abord votre autoconfig sur le conteneur, puis faites les remplacements par la suite. La dernière configuration définie (peu importe comment cela se passe) sera celle du conteneur.

J’ai finalement utilisé l’approche de Wiktor, mais avec une légère variation car je n’étais pas en mesure de passer à .NET 4.5 à temps pour mettre ma solution en production. Je n’ai donc pas pu utiliser l’enregistrement automatique.

Au lieu de cela, j’ai chargé d’abord une configuration XML à l’aide de

 container.LoadConfiguration(); 

Il est important de reconnaître que dans de nombreux cas, il existe une implémentation par défaut d’une abstraction, utilisée plus de 90% du temps. En fait, souvent, la valeur par défaut est toujours utilisée sauf lorsque des dépendances sont simulées à des fins de test. Par conséquent, il est judicieux de faciliter l’enregistrement des valeurs par défaut.

J’ai une convention dans mon équipe selon laquelle les valeurs par défaut sont enregistrées par une classe d’enregistrement au sein de l’assembly contenant les valeurs par défaut. La classe d’inscription est découvrable par reflection. Souvent, l’interface ou la classe abstraite sera dans un assemblage de contrats différent.

Les inscriptions sont toujours contenues dans la clause de sauvegarde:

 if (!container.IsRegistered()) { container.RegisterType() } 

J’ai également ajouté une méthode d’extension à IUnityContainer pour rendre cela un peu moins prolixe pour mes devs.

  public static IUnityContainer RegisterIfUnRegistered( this IUnityContainer container) where TImplementation : TAbstraction { if (!container.IsRegistered ()) { container.RegisterType(); } return container; //Make it fluent } 

Cela entraîne diverses surcharges, en prenant des enregistrements nommés et des enregistrements d’usines, etc.

Maintenant, les implémentations par défaut sont découvertes 99% du temps, mais elles peuvent être écrasées au format XML selon la suggestion de Wiktor.

Cela peut sembler un peu trop comme de la fumée et des miroirs. L’enregistrement automatique se sent souvent comme ça. Il est disponible à Castle Windsor et dans d’autres frameworks de conteneurs de dépendances depuis des années. Dommage que nous devions attendre 11 ans pour que l’offre soit disponible dans l’offre de Microsoft. Hmmm. Je digresse.

Tant que la convention d’enregistrement des valeurs par défaut dans l’assembly d’implémentation est respectée, il devient très facile d’effectuer des tests unitaires et de déboguer des enregistrements.

Rappelez-vous toutefois que le code qui effectue l’enregistrement en reflétant les assemblys ou en appelant directement les classes d’enregistrement doit être très proche de la méthode principale de votre exécutable. Ceci est votre racine de composition. Voir le blog de Mark Seeman pour plus d’informations sur l’dependency injection. Il a écrit le livre sur DI . Je recommande fortement ceci.