How can I register types as IPollingService<TContext>
so that they'll be decorated via container.RegisterDecorator(typeof(IPollingService<>), typeof(ContextAwarePollingServiceDecorator<>))
, but also register them as a collection of IPollingService
so that they'll be injected into the constructor of CompositePollingService
via container.RegisterCollection(typeof(IPollingService), types)
?
I have the following interfaces:
public interface IPollingService { Task Poll(); }
public interface IPollingService<TContext> : IPollingService
where TContext : CustomContext { TContext Context { get; } }
and a Composite-pattern implementation of IPollingService:
class CompositePollingService : IPollingService
{
private readonly IEnumerable<IPollingService> _pollingServices;
public CompositePollingService(IEnumerable<IPollingService> pollingServices) =>
_pollingServices = pollingServices;
public async Task Poll() =>
await Task.WhenAll(_pollingServices.Select(s => s.Poll()));
}
All my other implementations of IPollingService
actually implement IPollingService<TContext>
but I'm passing them into the CompositePollingService
constructor as IEnumerable<IPollingService>
because there will be a mix of IPollingService<TContext>
, and the CompositeService
only needs to know about IPollingService.Poll()
.
I add the types to a list conditionally based on configuration, and use the list to register the collection for the constructor of the CompositePollingService
:
List<Type> types = new List<Type>();
if (// config says to use TEST Context)
types.Add(typeof(PollingService<TestContext>)); // impl. of IPollingService<TContext>
if (// config says to use LIVE Context)
types.Add(typeof(PollingService<LiveContext>)); // impl. of IPollingService<TContext>
container.RegisterCollection(typeof(IPollingService), types);
I have a decorator for IPollingService<TContext>
:
class ContextAwarePollingServiceDecorator<TContext>
: IPollingService<TContext> where TContext: CustomContext
{
private readonly IPollingService<TContext> _decoratee;
public ContextAwarePollingServiceDecorator(IPollingService<TContext> decoratee)
=> _decoratee = decoratee;
public async Task Poll() {
// decoration here...
await _decoratee.Poll(cancellationToken);
}
public TContext Context => _decoratee.Context;
}
However, my decorator is not applied to my IPollingService<TContext>
implementations, when I register it like this:
container.RegisterDecorator(typeof(IPollingService<>),
typeof(ContextAwarePollingServiceDecorator<>));
How can I register types as IPollingService<TContext>
but also register them as a collection of IPollingService
so that they'll be injected into my CompositePollingService
implementation?
You can do this with the following code:
var ls = Lifestyle.Transient;
// Create a collection of InstanceProducer instances for IPollingService<T> registrations
var producers = new InstanceProducer[]
{
ls.CreateProducer<IPollingService<TestContext>, PollingService<TestContext>>(container),
ls.CreateProducer<IPollingService<LiveContext>, PollingService<LiveContext>>(container),
};
// Register a decorator that wraps around all IPollingService<T> instances
container.RegisterDecorator(typeof(IPollingService<>),
typeof(ContextAwarePollingServiceDecorator<>));
// Register the IEnumerable<IPollingService> that contains all IPollingService<T> instances
container.RegisterInstance(producers.Select(p => (IPollingService)p.GetInstance()));
// Register the composite
container.Register<IPollingService, CompositePollingService>(Lifestyle.Singleton);