Search code examples
c#castle-windsordecoratorcastle

Castle Windsor resolve ienumerable and name


I'm new to Castle Windsor (actually to DI) and trying to solve a scenario using windsor and i'm kind of stuck. To give an idea, there are 2 different remote sources from where I need to get some order info for a given customer no on the first attempt which is bit time consuming. The order info will never change in the future hence i would like to store that data in my local database for any subsequent use(s) which will increase the performance of my application.

It seems like the decorator pattern is a good candidate for this and below is my initial attempt.

public interface IOrderRepository
{
    IEnumerable<OrderInfo> Get(string customerNo);
    void Save(string customerNo, IEnumerable<OrderInfo> orders);
}

public class RealTimeRepo1 : IOrderRepository
{
     public IEnumerable<OrderInfo> Get(string customerNo)
     {
       /// Fetch the data from remote source 1
     }
     public void Save(string customerNo, IEnumerable<OrderInfo> orders)
     {
         /// You cannot update the order info in remote source
         throw new NotImplementedException();
     }
 }

public class RealTimeRepo2 : IOrderRepository
{
     public IEnumerable<OrderInfo> Get(string customerNo)
     {
       /// Fetch the data from remote source 2
     }
     public void Save(string customerNo, IEnumerable<OrderInfo> orders)
     {
         /// You cannot update the order info in remote source
         throw new NotImplementedException();
     }
 }

 public LocalOrderRepo : IOrderRepository
 {
     public IEnumerable<OrderInfo> Get(string customerNo)
     {
       /// Fetch the data from local data source

     }
     public void Save(string customerNo, IEnumerable<OrderInfo> orders)
     {
         /// Save the data on local data source
     }
 }

 public CacheOrderRepo : IOrderRepository
 {
     private readonly IEnumerable<IOrderRepository> realTimeRepos;
     private readonly IOrderRepository localRepo;

     public CacheOrderRepo(IEnumerable<IOrderRepository> realTime, IOrderRepository localRepo)
     {
           this.realTimeRepos = realTime;
           this.localRepo = localRepo;
     }

     public IEnumerable<OrderInfo> Get(string customerNo)
     {
         List<OrderInfo> orders = this.localRepo.Get(customerNo);
         if(orders == null) && (!orders.Any()
         {
             foreach(var r in this.realTimeRepos)
             {
                List<OrderInfo> t = r.Get(customerNo);
                if(t.Any())
                {
                  orders.AddRange(t);
                }
             }
             if(orders.Any())
             {
                 this.localRepo.save(customerNo, orders);
             }
         }
         return orders;
     }
     public void Save(string customerNo, IEnumerable<OrderInfo> orders)
     {
         /// Save the data on local data source
     }
 }

I hope the above code snippet gives an idea. My struggle is how to register this using windsor.

//regsiter
this._container.Kernal.Resolver.AddSubResolver(new  
    CollectionResolver(this._container.Kenrnal));

this._container.Register(
    Component.For<IOrderRepository>.ImplementedBy<RealTimeRepo1>().LifeStyle.Transient,
    Component.For<IOrderRepository>.ImplementedBy<RealTimeRepo2>().LifeStyle.Transient
 );

Using the collection subresolver i was able to register an ienumerable of RealTime repos 1 & 2. How i should register the local repo (i.e. my constructor parameter 2)?

Appreciate your help. I'm also open for suggestions with my understanding of the decorator pattern or castle windsor...


Solution

  • Firstly you will need to register the CollectionResolver.

    Secondly I suggest you either change the constructor of CacheOrderRepo to explicitly reference LocalOrderRepo or define a different abstraction (e.g. ILocalOrderRepo) for it.

    public class CacheOrderRepo : IOrderRepository
    {
        private readonly IEnumerable<IOrderRepository> realTimeRepos;
        private readonly LocalOrderRepo localRepo;
    
        public CacheOrderRepo(IEnumerable<IOrderRepository> realTime, LocalOrderRepo localRepo)
        {
            this.realTimeRepos = realTime;
            this.localRepo = localRepo;
        }
    

    The registration is then done by registering the composite (CacheOrderRepo) first, like this:

    var container = new WindsorContainer();
    container.Kernel.Resolver.AddSubResolver(new CollectionResolver(container.Kernel));
    container.Register(
        Component.For<IOrderRepository>().ImplementedBy<CacheOrderRepo>(),
        Component.For<IOrderRepository>().ImplementedBy<RealTimeRepo1>(),
        Component.For<IOrderRepository>().ImplementedBy<RealTimeRepo2>(),
        Component.For<LocalOrderRepo>().ImplementedBy<LocalOrderRepo>());
    
    var service = container.Resolve<IOrderRepository>();
    Assert.IsInstanceOf<CacheOrderRepo>(service);