2009-03-18 12 views

答えて

1

実際には、上書きするためにXMLファイルを結合し、デフォルトの流暢な登録を使用する素晴らしいソリューションが見つかりました。

fluent-APIは、implのフルネームをデフォルトキーとして使用します。オンザフライでは、Fluent-APIのキーコンベンションを模倣するために、xml-configのIDを上書きします。

次に、Kernel.ComponentRegisteredを聞きながらxml-configを登録します。

その後、xmlがまだサービスを定義していないサービスをcode-configから追加します。

(それはしばらく前だと、私はただのコードをコピー&ペースト。うまくいけば、あなたはそれが動作します。あなたが何か問題を見つけた場合、私は編集をやる)私は、サービスを登録する前に、その後

IList<Type> unnamedServices = new List<Type>(); 
IDictionary<string, Type> namedServices = new Dictionary<string, Type>(); 

ComponentDataDelegate registered = captureRegistrations(unnamedServices, namedServices); 

container.Kernel.ComponentRegistered += registered; 

// The method that captures the services 
private static ComponentDataDelegate captureRegistrations(
    IList<Type> unnamedServices, IDictionary<string, Type> namedServices) 
{ 
     return (key, handler) => 
       { 
        if (handler.ComponentModel.Name == handler.ComponentModel.Implementation.FullName) 
        { 
         unnamedServices.Add(handler.Service); 
        } 
        else 
        { 
         namedServices.Add(key, handler.Service); 
        } 
       }; 
} 

をコードでは、すでに登録されているかどうかを確認します。これをより簡単にする基本クラスも作成しました。このアプリケーションの設定です:あなたは非常に単純に上書きする必要がある場所でこれを行うことができます (ロギングCommons.Loggingからである)

public class WindsorConfigurationSkeleton 
{ 
    private static readonly ILog _log = LogManager.GetLogger(
     typeof(WindsorConfigurationSkeleton)); 

    internal static IWindsorContainer createWith(
     IRegistration[] customs, string configFile, params Func<IEnumerable<IRegistration>>[] methods) 
    { 
     IWindsorContainer container = new WindsorContainer(); 
     BugFix.Kernel = container.Kernel; 

     container.AddFacility("factory.support", new FactorySupportFacility()); 

     IList<Type> unnamedServices = new List<Type>(); 
     IDictionary<string, Type> namedServices = new Dictionary<string, Type>(); 

     ComponentDataDelegate registered = captureRegistrations(unnamedServices, namedServices); 

     container.Kernel.ComponentRegistered += registered; 

     if (customs != null) 
     { 
      container.Register(customs); 
     } 

     if (configFile != null) 
     { 
      tryAddXmlConfig(container, configFile); 
     } 

     container.Kernel.ComponentRegistered -= registered; 

     if (methods != null && methods.Length > 0) 
     { 
      container.Register(union(unnamedServices, namedServices, methods)); 
     } 

     return container; 
    } 

    private static ComponentDataDelegate captureRegistrations(
     IList<Type> unnamedServices, IDictionary<string, Type> namedServices) 
    { 
     return (key, handler) => 
       { 
        if (handler.ComponentModel.Name == handler.ComponentModel.Implementation.FullName) 
        { 
         var text = unnamedServices.Contains(handler.Service) ? "another" : "default"; 
         _log.Info(
          m => m(
            "Registered {2} service for {0} with {1}.", 
            handler.Service.GetDisplayName(), 
            handler.ComponentModel.Implementation.GetDisplayName(), 
            text 
            )); 

         unnamedServices.Add(handler.Service); 
        } 
        else 
        { 
         var text = namedServices.ContainsKey(key) ? "another" : "default"; 
         _log.Info(
          m => m(
            "Registered {3} service {0} with name '{1}' and {2}.", 
            handler.ComponentModel.Service, 
            handler.ComponentModel.Name, 
            handler.ComponentModel.Implementation.GetDisplayName(), 
            text 
            )); 
         namedServices.Add(key, handler.Service); 
        } 
       }; 
    } 

    protected static void tryAddXmlConfig(IWindsorContainer container, string filename) 
    { 
     var fi = Resources.GetFileFromResourceHierarchy(typeof(ApplicationContext).Namespace, filename); 
     if (fi == null) { 
      return; 
     } 
     var configFile = fi.FullName; 
     var xd = immitateFluentApiDefaultIdBehaviour(configFile); 
     container.Install(Configuration.FromXml(new StaticContentResource(xd.OuterXml))); 

    } 

    private static XmlDocument immitateFluentApiDefaultIdBehaviour(string configFile) 
    { 
     var xd = new XmlDocument(); 
     xd.Load(configFile); 

     foreach (
      XmlElement component in 
       xd.SelectNodes("/configuration/components/component[@type and (not(@id) or @id = '')]")) 
     { 
      var type = Type.GetType(component.GetAttribute("type"), true); 
      component.SetAttribute("id", type.FullName); 
     } 

     return xd; 
    } 

    private static IRegistration[] union(
     IList<Type> unnamed, IDictionary<string, Type> named, params Func<IEnumerable<IRegistration>>[] methods) 
    { 
     var all = new List<IRegistration>(); 
     foreach (var method in methods) 
     { 
      foreach (var registration in method()) 
      { 
       var registrationType = registration.GetType(); 
       if (registrationType.IsGenericTypeOf(typeof(ComponentRegistration<>))) 
       { 
        var componentType = registrationType.GetGenericArgumentsFor(typeof(ComponentRegistration<>))[0]; 

        var name = (string)registrationType.GetProperty("Name").GetValue(registration, null); 

        if (name != null) 
        { 
         if (named.ContainsKey(name)) 
         { 
          _log.Debug(
           m => m("Skipped registering default named component {0}.", name)); 
          continue; 
         } 
        } 
        else if (unnamed.Contains(componentType)) 
        { 
         _log.Debug(
          m => m("Skipped registering default component for type {0}.", componentType)); 
         continue; 
        } 

        all.Add(registration); 
       } 
       else 
       { 
        all.Add(registration); 
       } 
      } 
     } 

     return all.ToArray(); 
    } 
} 
0

はい、それはサービスのデフォルトの実装を再定義しません。あなたはなぜこれをやっているのですか?これを再定義するのではなく、まず登録してみてください。

もっと文脈を提供できますか?

+0

私は流暢な配線をオーバーライドするxmlファイルを持っています。しかし、私はxmlファイルを最初に読み込み、xmlファイルがそれらを再定義するときにコードから設定を追加しないことで、今解決しました。 –

+0

これはもっと良いアプローチです –

+0

@ラス:もっと具体的にすることができますか?私はここでも同じ問題があります。私はコア配線を持っており、コア配線を変更することなく別の実装に切り替える必要があります。 – Marcus

9

私はKrzysztofに同意しますが、これは通常良い考えではありません...しかし、OverWrite()がデフォルトのコンポーネントを上書きしないと、属性(つまり[Singleton])で定義されたライフスタイルを上書きします。

コンポーネントを交換する場合は、container.Kernel.RemoveComponent(string key)を使用して、新しいコンポーネントを登録することができます。

Here's an exampleここで、となります。

+1

RemoveComponentは必ずしも機能しないことに注意してください。 –

+0

@George:それについて詳しく説明できますか?削除しようとしているコンポーネントに他のコンポーネントが依存していない限り動作するはずです(意味があります)。 –

+0

ああ、わかりましたが、代わりに実装を指定する方法はありますか?私はグラフ全体を削除して再追加したくありません。 –

3

コンテナをデコレータで設定すると、デコレータが指示している実装を明示的に変更することができます。このような問題を解決するには、既存のコンポーネント(つまりシングルトン)が注入され、アプリケーションの存続期間中存在する可能性があります。

あなたが達成しようとしていることについて本当に多くの背景が必要です。


Here is more information about registering Decorators with Windsor

3

統合テストスイートでシステムを実行しているときにコンポーネントの実装を切り替える必要があり、container.Kernel.RemoveComponent()を使用できませんでした。だから私はsimple facilityで終わり、これは私のためにこれを処理する。

+0

残念ながら、登録が完了する前にすべての上書きを指定する必要があります –

11

:配線を行い

public class ApplicationConfiguration : WindsorConfigurationSkeleton 
{ 
    internal static WindsorServiceLocator create() 
    { 
     var container = createWith(null, "components-config.xml", coreServices, caches, roles); 
     return new WindsorServiceLocator(container); 
    } 

    internal static IEnumerable<IRegistration> coreServices() 
    { 
     yield return Component.For<ISystemClock>() 
      .ImplementedBy<PreciseSystemClock>() 
      .Parameters(Parameter.ForKey("synchronizePeriodSeconds").Eq("10")) 
      .LifeStyle.Singleton; 

     yield return Component.For<IMailService>() 
      .ImplementedBy<MailQueueService>() 
      .LifeStyle.Singleton; 
    } 

    internal static IEnumerable<IRegistration> caches() 
    { 
     yield return Component.For<IDataCache<ServiceAttributes>>() 
      .ImplementedBy<NoDataCache<ServiceAttributes>>() 
      .LifeStyle.Singleton; 

     // .... 
    } 
} 

基底クラスデフォルト実装。これは、統合テストの例です。どちらの実装も登録されていますが、登録したコードはデフォルトのコードを使用します。爆弾のように動作し、アプリケーションの残りの部分に影響を与えません:

 var sendMailStub = MockRepository.GenerateStub<ISendMail>(); 
     _container.Register(
      Component 
       .For<ISendMail>() 
       .Instance(sendMailStub) 
       .IsDefault() 
      ); 
+0

私が参照したウィンザーキャッスルアセンブリでは、IsDefault APIは使用できません。私はCastleを参照しています。コアアセンブリバージョン2.5.1.0。私は古いアセンブリを指していますか? – RBT

関連する問題