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