Register a decorator with a primitive data type

Coordinator
Oct 30, 2014 at 2:42 PM
Edited Oct 30, 2014 at 2:42 PM
When I need to pass in a primitive value to an implementation I can register the type with a delegate that will construct the required object.
[Fact]
public void Container_GetInstanceWithPrimitive_Succeeds()
{
    var container = new Container();
    container.Register<IMyType>(() => new MyType("value"));

    var result = container.GetInstance<IMyType>();

    Assert.IsType<MyType>(result);
}

public interface IMyType { }

public class MyType : IMyType 
{
    public MyType(string someSetting)
    {
    }
}
How can I achieve the same thing with a decorator; i.e. how can register a decorator that takes a primitive value in it's constructor?
[Fact]
public void Container_GetDecoratedInstanceWithPrimitive_Succeeds()
{
    var container = new Container();

    container.Register<IMyType>(() => new MyType("value"));
    container.RegisterDecorator(typeof(IMyType), ???? );

    var result = container.GetInstance<IMyType>();

    Assert.IsType<MyTypeDecorator>(result);
}

public class MyTypeDecorator : IMyType 
{
    public MyTypeDecorator(IMyType decorated, string someSetting)
    {
    }
}
Do I have to manage the decoration myself?
[Fact]
public void Container_GetDecoratedInstanceWithPrimitive2_Succeeds()
{
    var container = new Container();

    container.Register<IMyType>(
        () => new MyTypeDecorator(new MyType("value"), "value"));
            
    var result = container.GetInstance<IMyType>();

    Assert.IsType<MyTypeDecorator>(result);
}
Coordinator
Oct 30, 2014 at 2:56 PM
Edited Oct 30, 2014 at 11:48 PM
There's no built-in way to do that in Simple Injector. There are a few options:

1. Hide the primitive value behind an abstraction.

This is especially useful for instance in the case where you can move some logic with that primitive. Great example is injecting an IConnectionFactory instead of injecting an string connectionString.
container.RegisterSingle<IConnectionFactory>(new ConnectionFactory("conStr"));
container.Register<IMyType, MyType>();
container.RegisterDecorator(typeof(IMyType), typeof(MyTypeDecorator));
2. Move the primitive value out of the constructor into a property.

This is useful if there is no logic to abstract on behalf of that primitive and the decorator is the only place in the system where that value is used. Downside is that you introduce temporal coupling.
container.Register<IMyType>(() => new MyType("value"));
container.RegisterDecorator(typeof(IMyType), typeof(MyTypeDecorator));
container.RegisterInitializer<MyTypeDecorator>(instance => instance.Value = "value");
3. Build the object graph manually.

Auto-wiring is meant as a mean to reduce the amount of maintenance needed on your composition root, and keeping this control in the container allows certain specific optimizations or special framework features to be applied (such as conditional decoration, context based injection, etc). If you don't need these features, and don't expect this type and it's decorator to be subject to frequent change, manual registration is a very valid option. You already showed an example of this, but here's it again for completeness:
container.Register<IMyType>(() => new MyTypeDecorator(new MyType("value"), "value"));
4. Override the container's constructor injection behavior.

The container allows overriding the constructor parameter injection behavior, which allows injecting primitive dependencies with Simple Injector.

By overriding the default IConstructorVerificationBehavior and IConstructorInjectionBehavior we could let a custom value be injected. For instance:
internal class MyTypeDecoratorVerificationBehavior : IConstructorVerificationBehavior {
    private IConstructorVerificationBehavior decorated;
    public MyTypeDecoratorVerificationBehavior(IConstructorVerificationBehavior decorated) {
        this.decorated = decorated;
    }
    public void Verify(ParameterInfo parameter) {
        if (!parameter.DeclaringType != typeof(MyTypeDecorator)) {
            this.decorated.Verify(parameter);
        }
    }
}

internal class MyTypeDecoratorInjectionBehavior : IConstructorInjectionBehavior {
    private IConstructorInjectionBehavior decorated;
    public MyTypeDecoratorInjectionBehavior (IConstructorInjectionBehavior decorated) {
        this.decorated = decorated;
    }
    public Expression BuildParameterExpression(ParameterInfo parameter) {
        if (!parameter.DeclaringType != typeof(MyTypeDecorator) || parameter.Name != "value") {
            return this.decorated.BuildParameterExpression(parameter);
        }

        return Expression.Constant("value");
    }
}

container.Options.ConstructorVerificationBehavior =
    new MyTypeDecoratorVerificationBehavior(options.ConstructorVerificationBehavior);

container.Options.ConstructorInjectionBehavior =
    new MyTypeDecoratorInjectionBehavior(options.ConstructorInjectionBehavior);
Although overriding this behavior can be very useful, it's quite overkill in this scenario :-)
Marked as answer by qujck on 10/30/2014 at 7:59 AM
Coordinator
Oct 31, 2014 at 10:30 AM
Edited Oct 31, 2014 at 10:38 AM
I was considering the same option last night.

I have some cached query results (ASP.NET session cache) and I want to add a feature that certain cached results are cleared by certain commands/other scenarios.

I have a query decorator for caching query results, what I want to create is a command decorator that will remove a cached query when a certain command is executed (I can also decorate a command twice if it should clear 2 cached values).

So each instance of a decorator needs to know the name (key) of the session object it is affecting - and hence the string being passed into the constructor.

SessionKeyInjectionBehaviour & SessionKeyInjectionVerificationBehaviour probably can't be made to work in this instance.

I think option 3 may be the best option - unless you have any other suggestions?
Coordinator
Oct 31, 2014 at 10:38 AM