This helpful article from David Haydn (EDIT: scam link removed, it could have been this article) shows how you can use the InjectionConstructor class to help y
I knocked up a fairly crude extension method for this, which behaved as expected when I ran it:
public static class UnityExtensions
{
public static IUnityContainer Decorate(this IUnityContainer container, params InjectionMember[] injectionMembers)
where TDecorator : class, TInterface
{
return Decorate(container, null, injectionMembers);
}
public static IUnityContainer Decorate(this IUnityContainer container, LifetimeManager lifetimeManager, params InjectionMember[] injectionMembers)
where TDecorator : class, TInterface
{
string uniqueId = Guid.NewGuid().ToString();
var existingRegistration = container.Registrations.LastOrDefault(r => r.RegisteredType == typeof(TInterface));
if(existingRegistration == null)
{
throw new ArgumentException("No existing registration found for the type " + typeof(TInterface));
}
var existing = existingRegistration.MappedToType;
//1. Create a wrapper. This is the actual resolution that will be used
if (lifetimeManager != null)
{
container.RegisterType(uniqueId, lifetimeManager, injectionMembers);
}
else
{
container.RegisterType(uniqueId, injectionMembers);
}
//2. Unity comes here to resolve TInterface
container.RegisterType(new InjectionFactory((c, t, sName) =>
{
//3. We get the decorated class instance TBase
var baseObj = container.Resolve(existing);
//4. We reference the wrapper TDecorator injecting TBase as TInterface to prevent stack overflow
return c.Resolve(uniqueId, new DependencyOverride(baseObj));
}));
return container;
}
}
And in your setup:
container.RegisterType();
// Wrap ProductRepository with CachingProductRepository,
// injecting ProductRepository into CachingProductRepository for
// IProductRepository
container.Decorate();
// Wrap CachingProductRepository with LoggingProductRepository,
// injecting CachingProductRepository into LoggingProductRepository for
// IProductRepository
container.Decorate();