2013-04-29 12 views
6

を依存関係を変更する私はいくつかのデータを取得するためにインターネットサービスにアウト呼び出すクラスを持っている:HttpDataProviderとFileDataProvider:をプログラム的に城ウィンザーで

public class MarketingService 
{ 
    private IDataProvider _provider; 
    public MarketingService(IDataProvider provider) 
    { 
     _provider = provider; 
    } 

    public string GetData(int id) 
    { 
     return _provider.Get(id); 
    } 
} 

現在、私は2つのプロバイダを持っています。通常、私はHttpDataProviderに接続しますが、外部Webサービスが失敗した場合は、FileDataProviderにバインドするようにシステムを変更したいと思います。ような何か:これはMarketingServiceの将来のすべてのインスタンスを実行してきたので、

public string GetData(int id) 
{ 
    string result = ""; 

    try 
    { 
     result = GetData(id); // call to HttpDataProvider 
    } 
    catch (Exception) 
    { 
     // change the Windsor binding so that all future calls go automatically to the 
     // FileDataProvier 
     // And while I'm at it, retry against the FileDataProvider  
    } 

    return result; 
} 

は自動的にFileDataProviderまで配線されます。誰もがその場でウィンザーのバインディングを変更する方法を知っていますか?

答えて

6

一つの解決策は、セレクタ

public class ForcedImplementationSelector<TService> : IHandlerSelector 
{ 
    private static Dictionary<Type, Type> _forcedImplementation = new Dictionary<Type, Type>(); 

    public static void ForceTo<T>() where T: TService 
    { 
     _forcedImplementation[typeof(TService)] = typeof(T); 
    } 

    public static void ClearForce() 
    { 
     _forcedImplementation[typeof(TService)] = null; 
    } 

    public bool HasOpinionAbout(string key, Type service) 
    { 
     return service == typeof (TService); 
    } 

    public IHandler SelectHandler(string key, Type service, IHandler[] handlers) 
    { 
     var tService = typeof(TService); 
     if (_forcedImplementation.ContainsKey(tService) && _forcedImplementation[tService] != null) 
     { 
      return handlers.FirstOrDefault(handler => handler.ComponentModel.Implementation == _forcedImplementation[tService]); 
     } 

     // return default 
     return handlers[0]; 
    } 
} 

テストと使用

[TestFixture] 
public class Test 
{ 
    [Test] 
    public void ForceImplementation() 
    { 
     var container = new WindsorContainer(); 

     container.Register(Component.For<IFoo>().ImplementedBy<Foo>()); 
     container.Register(Component.For<IFoo>().ImplementedBy<Bar>()); 

     container.Kernel.AddHandlerSelector(new ForcedImplementationSelector<IFoo>()); 

     var i = container.Resolve<IFoo>(); 
     Assert.AreEqual(typeof(Foo), i.GetType()); 

     ForcedImplementationSelector<IFoo>.ForceTo<Bar>(); 

     i = container.Resolve<IFoo>(); 
     Assert.AreEqual(typeof(Bar), i.GetType()); 


     ForcedImplementationSelector<IFoo>.ClearForce(); 

     i = container.Resolve<IFoo>(); 
     Assert.AreEqual(typeof(Foo), i.GetType()); 
    } 
} 
+0

私たちはこの実装を成功させましたが、消費量の多いスレッドが辞書で動作していたので、ConcurrentDictionaryに変更してここで推奨されるスレッドセーフにしました:https://blogs.msdn.microsoft.com/tess/2009/12/21/high-cpu-in-net-app-a-static-generic-dictionary / – Calum

0

を使用することになり代わりにプロキシを作成することができます。

public class AutoSelectingDataProvider : IDataProvider 
{ 
    public AutoSelectingDataPovider(HttpDataProvider httpDataProvider, FallBackDataProvider fallBackProvider) 
    { 
     _httpDataProvider = httpDataProvider; 
     _fallBackDataProvider = fallBackDataProvider; 
    } 


    public string GetData(int id) 
    { 
     try 
     { 
      return _httpDataProvider.GetData(id); 
     } 
     catch (Exception) 
     { 
      return _fallBackDataProvider.GetData(id); 
     } 
    return result; 
    } 
} 


container.Register(
    Component.For<HttpDataProvider>(), 
    Component.For<FallBackDataProvider>(), 
    Component.For<IDataProvider>().ImplementedBy<FallBackDataProvider>()); 

これは常に最初からデータを取得しようとします失敗した場合はHttpDataProviderがフォールバックを使用します。あなたが状態を導入することができますし、失敗の後に常にフォールバックを使用することができます。これにより、コンテナから新しいIDataProviderを取得することなく、アプリケーションでIDataProviderを使用し続けることができます。

関連する問題