1

Je suis un Castle n00b, et j'utilise l'API Fluent de Castle Windsor pour enregistrer automatiquement les implémentations dans des services basés sur une convention de dénomination (quelque chose est implémenté par Something). Une chose que je voulais prendre en charge est que l'auto-enregistrement ramasse les dépendances qui se trouvent dans des DLL séparées, et les enregistre automatiquement. Donc: IFoo est implémenté par Foo (tous les deux dans Foo.dll), et Foo dépend de IBar, qui est dans Bar.dll.Castle Windsor et enregistrement automatique

J'ai le code suivant écrit pour effectuer l'auto-enregistrement. Cela semble fonctionner, mais je me demande si j'ai trop travaillé moi-même. Existe-t-il un moyen plus simple d'accomplir la même chose?

private static void EnsureRegistered(Type t, IWindsorContainer container) 
    { 
     if (!container.Kernel.HasComponent(t) && (!(t.Assembly.FullName.StartsWith("System") || t.Assembly.FullName.StartsWith("mscorlib")))) 
     { 
      bool registeredAtLeastOneComponent = false; 

      container.Register(AllTypes.Pick(). 
        FromAssembly(t.Assembly).If(delegate(Type t2) 
         { 
          //auto-registers all types that implement an interface where 
          //the name of the interface is the same as the class, minus the 'I' 
          //ex: EchoService is auto-registered as handler of IEchoService 
          Type[] interfaces = t2.GetInterfaces(); 
          bool shouldRegister = false; 
          foreach(Type interfaceType in interfaces) 
          { 
           shouldRegister = t2.Name.Equals(interfaceType.Name.Substring(1)) 
                && (!container.Kernel.HasComponent(interfaceType)); 
           registeredAtLeastOneComponent = registeredAtLeastOneComponent || shouldRegister; 
           if (shouldRegister) 
            break; 
          } 
          return shouldRegister; 

         }).WithService.Select(delegate(Type type, Type baseType) 
         { 
          Type serviceType = null; 
          Type[] interfaces = type.GetInterfaces(); 
          foreach(Type interfaceType in interfaces) 
          { 
           if (!type.Name.Equals(interfaceType.Name.Substring(1))) continue; 
           serviceType = interfaceType; 
           break; 
          } 

          return new Type[] {serviceType}; 

         })); 

      if (!registeredAtLeastOneComponent) 
       return; 

      //for each of the items in the graph, if they have see if they have dependencies 
      //in other assemblies that aren't registered, register those dependencies as well 
      foreach(GraphNode registered in container.Kernel.GraphNodes) 
      { 
       if (!(registered is Castle.Core.ComponentModel)) 
        continue; 

       Castle.Core.ComponentModel registeredComponent = registered as Castle.Core.ComponentModel; 

       foreach(ConstructorCandidate constructor in registeredComponent.Constructors) 
       { 
        foreach(DependencyModel dep in constructor.Dependencies) 
        { 
         EnsureRegistered(dep.TargetType, container); 
        } 
       } 
      } 
     } 
    } 

Répondre

2

Cela dépend vraiment de la façon dont vous structurez et nommez vos composants ... si vous gardez certaines conventions simples (par exemple tous les services de composants sous la rubrique « MyApp.Services » namespaces et leurs mises en œuvre sous « MyApp.Services.Impl ") vous pourriez réduire considérablement cette complexité (voir par exemple ayende1, ayende2). En outre, IMO l'utilité de cela est plutôt limitée, sauf pour les cas les plus simples ... par exemple certains services que vous souhaitez enregistrer sans interface de service, certains services nécessitent une configuration, les remplacements de service, etc. auquel cas cette ne fonctionnera pas.

+0

Merci pour la réponse. Ce que je fais est d'introduire un conteneur dans certaines applications héritées, et d'aller sans friction lors de l'utilisation du conteneur (à condition qu'ils soient conformes à la convention 'IBar est implémentée par Bar'). Et convenu de: scénarios complexes. Essayer de frapper le cas de 80% ici, cependant. –

+0

Dans ce cas, le code devrait très bien servir son but! –

+0

Merci. Comme je l'ai dit, je cherchais principalement à voir si je manquais un moyen plus simple. Et comme vous l'avez souligné, une façon de simplifier les choses serait de simplifier les choses autour du conteneur :-) –

0

Je ne sais pas si cela répond à votre question, mais c'est ce que j'ai fait pour enregistrer automatiquement mes services.

 // Auto-Register Services as Singletons 
     container.Register(
      AllTypes.FromAssembly(typeof(BaseService).Assembly).Pick() 
        .WithService.DefaultInterfaces() 
        .Configure(s => s.LifestyleSingleton())); 

Tous mes services héritent d'un BaseService (classe abstraite) ainsi qu'une interface - IService. Cela lierait automatiquement la classe Concrete Service à son interface et la rendrait utilisable dans le conteneur.

Questions connexes