1

캐슬 윈저의 Fluent API를 사용하여 명명 규칙을 기반으로 서비스에 대한 구현을 자동 등록합니다 (어떤 것이 Something에 의해 구현 됨). 한 가지 지원하고자하는 것은 자동 등록이 별도의 dll에있는 종속성을 선택하고 자동 등록하는 것입니다.캐슬 윈저 및 자동 등록

So : IFoo는 Foo (둘 다 Foo.dll)에서 구현되며 Foo는 Bar.dll에있는 IBar에 종속됩니다.

다음 코드는 실제로 자동 등록을 수행하도록 작성되었습니다. 그것은 효과가있는 것 같지만, 내가 너무 많은 일을했는지 ​​궁금합니다. 동일한 것을 성취하는 더 간단한 방법이 있습니까?

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); 
        } 
       } 
      } 
     } 
    } 

답변

2

정말 당신이 "MyApp.Services.Impl 아래에있는"MyApp.Services "네임 스페이스와 그 구현에 따라 몇 가지 간단한 규칙 (즉, 모든 구성 요소 서비스를 유지하는 경우 ... 구조 및 구성 요소의 이름을 방법에 따라 달라집니다 ")이 복잡성을 크게 줄일 수 있습니다 (예 : ayende1, ayende2 참조).

또한 IMO는 가장 단순한 경우를 제외하고는 다소 제한적입니다. 예를 들어 서비스 인터페이스없이 등록하려는 일부 서비스, 일부 서비스에는 구성, 서비스 재정의 등이 필요합니다. 작동하지 않습니다.

+0

답변 해 주셔서 감사합니다. 내가하고있는 일은 일부 레거시 앱에 컨테이너를 도입하고 컨테이너를 사용할 때 무 마찰 ('IBar은 Bar Convention으로 구현 됨'을 준수하는 한)으로 진행하는 것입니다. 그리고 합의 : 복잡한 시나리오. 80 %의 경우를 여기에서 칠하려고 노력한다. –

+0

그 경우 코드가 그 목적을 잘 수행해야합니다! –

+0

감사합니다. 내가 말했듯이, 나는 주로 내가 더 간단한 길을 잃어 버렸는지를보기 위해 찾고 있었다. 그리고 여러분이 지적했듯이, 물건을 더 단순하게 만드는 한 가지 방법은 컨테이너 주변의 물건을 단순화하는 것입니다 :-) –

0

이 질문에 대한 답변이 확실하지 않지만 이것이 내 서비스를 자동 등록한 것입니다.

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

내 모든 서비스는 BaseService (추상 클래스)뿐만 아니라 인터페이스에서 상속 - IService합니다. 이렇게하면 자동으로 Concrete Service 클래스가 해당 인터페이스에 바인딩되어 컨테이너에서 사용할 수있게됩니다.

관련 문제