1

Closed

Allow injecting Func<T> in decorators in RegisterDecorator

description

The current version of the Simple Injector Extensions contain RegisterDecorator extension methods that allow decorating instances with decorators.
 
In some scenarios it will be beneficial to delay building of the dependency graph. For decorators this means that instead of building up the entire dependency graph (decorator + wrapped instance), only the decorator should be created, injected with a factory that allows to create the wrapped at a later time. This question came up on Stackoverflow multiple times (see questions 10955077 and 10304023). Delaying the dependency graph is for instance needed when we need to execute the wrapped instance asynchronously, or when we want to execute the wrapped instance inside a lifetime scope.
 
The answers to these Stackoverflow questions contain a registration that can be generalized to:
 
container.ExpressionBuilt += (s, e) =>
{
var type = e.RegisteredServiceType;
 
if (type.IsGenericType &&
    type.GetGenericTypeDefinition() == typeof(ICommandHandler<>))
{
    var instanceCreator = Expression.Lambda(
        Expression.Convert(e.Expression, type)).Compile();
 
    var constructor =
        typeof(LifetimeScopeCommandHandlerProxy<>).MakeGenericType(
            type.GetGenericArguments()[0])
            .GetConstructors().Single();
 
    e.Expression = Expression.New(constructor,
        Expression.Constant(instanceCreator));
}
};
 
This however is some nasty code, especially for a problem that seems to be common. Besides, this code does not behave correctly when working with generic type constraints, generic type swapping, and other nasty generic type complexities. It would be good to allow the RegisterDecorator methods allow to delay building the dependency graph by injecting a Func<T> instead of just the dependency itself. Adding this feature is a non-breaking change.
Closed Jun 30, 2012 at 10:43 PM by dot_NET_Junkie

comments

dot_NET_Junkie wrote Jun 10, 2012 at 11:47 AM

The statement that this feature is a non-breaking change is incorrect. Adding this feature could result in breaking clients. Take for instance a decorator for IService, that contains a Func<IService> that is configured in the container and gets injected in the current version. With this new feature we would change the meaning of what that Func<IService> dependency is, and this therefore could break clients.

That said, the change of breaking clients is small, and what we can do is accept only a IService or an Func<IService>, but not both. This won’t really solve the problem, but allows the application to fail fast, when a decorator is configured in that way.

wrote Jun 30, 2012 at 10:43 PM

Resolved with changeset 92340.