2013-04-29 34 views
6

Tôi có một lớp học mà các cuộc gọi ra một dịch vụ internet để có được một số dữ liệu:programatically thay đổi phụ thuộc vào Lâu đài Windsor

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

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

Hiện nay tôi có hai nhà cung cấp: HttpDataProvider và FileDataProvider. Thông thường tôi sẽ kết nối tới HttpDataProvider nhưng nếu dịch vụ web bên ngoài không thành công, tôi muốn thay đổi hệ thống để liên kết với FileDataProvider. Một cái gì đó như:

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

Vì vậy, khi điều này đã được thực thi, tất cả các trường hợp tiếp theo của MarketingService sẽ tự động được kết nối với FileDataProvider. Có ai biết làm thế nào để thay đổi một ràng buộc Windsor trên bay?

Trả lời

6

Một giải pháp sẽ được sử dụng selector

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

thử nghiệm và sử dụng

[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

Chúng tôi đã sử dụng triển khai này thành công, tuy nhiên các chủ đề tiêu thụ hàng đầu của chúng tôi đã làm việc với từ điển, vì vậy chúng tôi đã thay đổi nó thành ConcurrentDictionary để làm cho chuỗi đó an toàn như được đề xuất tại đây: https://blogs.msdn.microsoft.com/tess/2009/12/21/cpu-in-net-app-sử dụng-a-static-generic-dictionary / – Calum

0

Hoặc bạn có thể tạo ra một proxy:

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

này sẽ luôn luôn đầu tiên cố gắng để lấy dữ liệu từ HttpDataProvider nếu không thành công sử dụng dự phòng. Nếu bạn muốn bạn có thể giới thiệu nhà nước và sau khi thất bại luôn luôn sử dụng dự phòng. Bằng cách này, bạn có thể tiếp tục sử dụng IDataProvider trong ứng dụng của mình mà không cần phải lấy một ID mới từ thùng chứa.

Các vấn đề liên quan