2011-02-10 1 views
2

En Autofac on peut faire ce qui suit pour obtenir tous les services enregistrés:Est-il possible dans Autofac de résoudre tous les services pour un type, même s'ils ont été enregistrés avec un nom ou une clé?

IEnumerable<MyClass> all = Context.Resolve<IEnumerable<MyClass>>() 

Cependant, cela ne comprend pas ceux qui ont été enregistrés comme des services désignés. En regardant la source Autofac, il semble que c'est parce que les services sont interrogés pour une résolution basée sur un TypedService ou un KeyedService.

Y at-il un moyen de résoudre tous les services à un IEnumerable, indépendamment du fait qu'ils ont été enregistrés avec un nom ou non?

Répondre

5

La meilleure option est d'enregistrer ici les articles en utilisant la clé et le service « typé » régulier:

builder.Register<CupOfT>() 
    .As<IBeverage>() 
    .Keyed<IBeverage>("someKey"); 

Vous pouvez ensuite résoudre simplement IEnumerable<IBeverage> pour obtenir le résultat que vous êtes après, tout en les résolvant par clé (ou nom) est également supporté.

Si vous êtes préoccupé par le maintien d'un enregistrement par défaut particulier pour IBeverage, utilisez simplement PreseveExistingDefaults() sur les autres (ou assurez-vous que votre choix par défaut est enregistré en dernier).

HTH!

Nick

+0

Une aide rapide suivie d'une réponse différée de l'OP n'est pas très zen, de grandes excuses! J'aurais dû mentionner dans ma question que je ne contrôle pas nécessairement toutes les inscriptions. Cela fait partie d'une abstraction au-dessus d'Autofac, dans un cadre utilisé pour construire des sites (Umbraco 5) afin que notre framework puisse être utilisé dans des solutions tierces ayant une dépendance commerciale ou autre sur un autre conteneur ou une autre version d'Autofac sans notre propre code d'enregistrement interne étant spécifique au fournisseur. –

1

J'ai écrit une méthode qui semble fonctionner; J'apprécierais la rétroaction s'il y a une façon intégrée de le faire dans Autofac. Dans l'exemple ci-dessous, le champ _context est de type IComponentContext.

public IEnumerable<T> ResolveAll<T>() 
    { 
     // We're going to find each service which was registered 
     // with a key, and for those which match the type T we'll store the key 
     // and later supplement the default output with individual resolve calls to those 
     // keyed services 
     var allKeys = new List<object>(); 
     foreach (var componentRegistration in _context.ComponentRegistry.Registrations) 
     { 
      // Get the services which match the KeyedService type 
      var typedServices = componentRegistration.Services.Where(x => x is KeyedService).Cast<KeyedService>(); 
      // Add the key to our list so long as the registration is for the correct type T 
      allKeys.AddRange(typedServices.Where(y => y.ServiceType == typeof (T)).Select(x => x.ServiceKey)); 
     } 

     // Get the default resolution output which resolves all un-keyed services 
     var allUnKeyedServices = new List<T>(_context.Resolve<IEnumerable<T>>()); 
     // Add the ones which were registered with a key 
     allUnKeyedServices.AddRange(allKeys.Select(key => _context.ResolveKeyed<T>(key))); 

     // Return the total resultset 
     return allUnKeyedServices; 
    } 
+1

Plutôt que d'utiliser 'Resolve()' et 'ResolveKeyed()' ici, vous pourrait envisager d'utiliser la méthode 'ResolveComponent()'. Cela permettra de mieux gérer les cas où plusieurs implémentations existent pour le même service (ou avec la même clé.) –

0

Il semblerait que vous pouvez combiner les As<T>() méthodes et Named<T>() méthodes comme indiqué ci-dessous:

[TestMethod] 
    public void ResolveTests() 
    { 
     var builder = new ContainerBuilder(); 
     builder.RegisterType<ClassA1>().As<IClassA>().Named<IClassA>("1"); 
     builder.RegisterType<ClassA2>().As<IClassA>().Named<IClassA>("2"); 
     builder.RegisterType<ClassA3>().As<IClassA>().Named<IClassA>("3"); 
     var container = builder.Build(); 

     var allInstances = container.Resolve<IEnumerable<IClassA>>(); 
     allInstances.Count().Should().Be(3); 

     container.ResolveNamed<IClassA>("1").Should().BeAssignableTo<ClassA1>(); 
     container.ResolveNamed<IClassA>("2").Should().BeAssignableTo<ClassA2>(); 
     container.ResolveNamed<IClassA>("3").Should().BeAssignableTo<ClassA3>(); 
    } 
Questions connexes