2013-04-29 10 views
6

Ich habe eine Klasse, die zu einem Internet Service ruft einige Daten zu erhalten:programmatisch eine Abhängigkeit in Schloss Windsor ändern

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

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

Zur Zeit habe ich zwei Anbieter: HttpDataProvider und FileDataProvider. Normalerweise werde ich an den HttpDataProvider anschließen, aber wenn der externe Webdienst fehlschlägt, möchte ich das System ändern, um an den FileDataProvider zu binden. Etwas wie:

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

Also, wenn diese alle zukünftigen Instanzen von Marketingservice ausgeführt wurde, wird automatisch auf die FileDataProvider verdrahtet werden. Weiß jemand, wie man eine Windsor-Bindung im laufenden Betrieb ändert?

Antwort

6

Eine Lösung wäre Selektor

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

-Test und Verwendung

[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

Wir haben diese Implementierung mit Erfolg verwendet, aber unsere Top-Threads arbeiteten mit dem Wörterbuch, also änderten wir es in ein ConcurrentDictionary, um es wie hier empfohlen threadsicher zu machen: https://blogs.msdn.microsoft.com/tess/2009/12/21/high-cpu-im-netz-app-using-a-static-generic-dictionary / – Calum

0

Alternativ verwenden Sie einen Proxy schaffen könnte:

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

Dies wird immer zuerst versuchen, von bekommen Daten der HttpDataProvider, falls nicht erfolgreich, den Fallback verwenden. Wenn Sie möchten, können Sie den Status einführen und nach einem Fehler immer den Fallback verwenden. Auf diese Weise können Sie den IDataProvider weiterhin in Ihrer Anwendung verwenden, ohne dass Sie eine neue aus dem Container abrufen müssen.

Verwandte Themen