4

je l'architecture suivante où une classe de service public référence à une classe interne d'assistance existe dans un autre ensemble:Injecter une classe d'aide interne tout en résolvant une classe publique

ApplicationAssembly { 
    public class Widget { 
    public Widget(ReferencedAssembly.Service service) { ... } 
    } 
} 

ReferencedAssembly { 
    public class Service { 
    public Service(Helper helper) { ... } 
    } 
    class Helper { ... } 
} 

(je me rends compte que je ne peux pas mettre classe interne dans les arguments du constructeur d'une classe publique - j'essaie juste d'illustrer le motif IoC que je vais après.)

Le problème est que ApplicationAssembly ne peut pas voir ReferencedAssembly.Helper, donc il peut ' t être enregistré dans mon conteneur IoC (autofac dans ce cas). Par conséquent, Helper ne peut pas être résolu lorsque j'essaie de résoudre le service. Quelle est ma meilleure option ici?

Option 1. Supprimez Helper du constructeur de Service et recréez-le explicitement dans le constructeur. Je n'aime pas cette option parce qu'elle brise le paradigme de l'IoC.

Option 2. Faites en sorte que Helper implémente une interface publique IHelper, puis ajoutez un module public dans ReferencedAssembly qui enregistre Helper en tant que IHelper. Je n'aime pas cette option car elle nécessite que ApplicationAssembly connaisse trop de détails d'implémentation à propos de Service, et si l'utilisateur oublie d'enregistrer ce module au démarrage, tout se casse.

Option 3. Créez un constructeur statique public sur Service qui crée un deuxième conteneur IoC spécifiquement pour ReferencedAssembly et y inscrit Helper. Supprimez Helper du constructeur de Service et résolvez-le dans le constructeur en utilisant le deuxième conteneur IoC. Cela semble être ma meilleure option, mais nécessite plus de code "plomberie" que les autres. Je ne suis pas non plus un grand fan des constructeurs statiques publics.

Option 4. Changez mon architecture pour autre chose.

+3

Qu'en est la solution la plus simple et la meilleure (rasoir d'Occam): il suffit de rendre le type public –

+0

+1 à cela aussi :) –

Répondre

11

La manière d'enregistrer des types internes avec Autofac consiste à inclure un Autofac Module dans l'assemblage avec les types internes, et enregistrer le module avec le conteneur. Parce que le module est dans le même assembly, il peut configurer le ContainerBuilder avec les types internes.

Je pense que la meilleure option est de faire Service implémenter une interface publique, puis rendre la classe Service que vous avez actuellement interne. Autofac instanciera avec plaisir une classe interne pour fournir une interface publique.

L'autre option (pour permettre Service de prendre une dépendance du constructeur sur un type interne) est de rendre le constructeur de Service interne, puis utiliser un détecteur de constructeur dans l'enregistrement de type Service:

builder.RegisterType<Service>() 
    .FindConstructorsWith(new BindingFlagsConstructorFinder(BindingFlags.NonPublic)); 
+2

Il ne peut pas résoudre BindingFlagsConstructorFinder dans autofac 3.5. Savez-vous comment résoudre ce problème? –

+2

Pour tous ceux qui sont arrivés ici et espéraient que BindingFlagsConstructorFinder était une classe existante, j'ai extrait ceci de DefaultConstructorFinder et je l'ai modifié pour trouver les constructeurs internes: FindConstructorsWith (new InternalConstructorFinder); où InternalConstructorFinder est: public class InternalConstructorFinder: IConstructorFinder {public ConstructorInfo [] FindConstructeurs (Type t) => t.GetTypeInfo(). DeclaredConstructors.Where (c =>! C.IsPrivate &&! C.IsPublic) .ToArray(); } ' – Jamey

+1

' BindingFlagsConstructorFinder' était en Autofac 2.x (cette réponse est un peu démodée :-)) - vous pouvez voir la source originale [ici] (https://www.symbolsource.org/Public/Metadata/Default/ Projet/Autofac/2.2.4.900/Release/net-3.5/Autofac/Autofac/Noyau/Activateurs/Reflection/BindingFlagsConstructorFinder.cs? ImageName = Autofac). –

Questions connexes