Larrifax
Larrifax

Reputation: 408

Simple Injector registration of Composite combining open and closed generic implementations

I'm working on creating validation decorators for my commands, but I'm having trouble with registering the types with the Simple Injector DI container.

The case is:

According to the Simple Injector documentation, one should create a CompositeCommandValidator in cases like these. I've mimicked the implementation mentioned in the documentation, meaning that my ValidationCommandHandlerDecorator still can have a dependency on ICommandValidator<TCommand> instead of an IEnumerable.

Then there is the configuration of the Simple Injector container. My configuration currently looks like this:

_container.RegisterManyForOpenGeneric(
    typeof(ICommandValidator<>), 
    _container.RegisterAll,
    typeof (ICommandValidator<>).Assembly);

_container.RegisterAllOpenGeneric(
    typeof(ICommandValidator<>),
    typeof(DataAnnotationsCommandValidator<>));

_container.RegisterSingleOpenGeneric(
    typeof(ICommandValidator<>), 
    typeof(CompositeCommandValidator<>));

However, when I debug the application, only the specific validators are injected into the CompositeCommandValidator (I'm missing the DataAnnotationsCommandValidator). I've tried a few different configurations, but to no avail. How should I configure Simple Injector to get the correct behavior?

Upvotes: 4

Views: 595

Answers (1)

Steven
Steven

Reputation: 172786

UPDATE for Simple Injector v4:

// Register validators as sequence
_container.Collection.Register(
    typeof(ICommandValidator<>),
    typeof (ICommandValidator<>).Assembly);

// Append the data annotations validator as last element to the sequence
_container.Collection.Append(
    typeof(ICommandValidator<>),
    typeof(DataAnnotationsCommandValidator<>));

// Register the composite that will wrap the sequence.
_container.Register(
    typeof(ICommandValidator<>), 
    typeof(CompositeCommandValidator<>));

Original Simple Injector v2 answer:

The RegisterManyForOpenGeneric method will only scan the assemblies for non-generic implementations of the given interface, because open-generic implementations often need special care. There are basically two options here.

Option 1:

var types = OpenGenericBatchRegistrationExtensions.GetTypesToRegister(
    _container,
    typeof (ICommandValidator<>),
    AccessibilityOption.PublicTypesOnly,
    typeof (ICommandValidator<>).Assembly)
    .ToList();

types.Add(typeof(DataAnnotationsValidator<>));

_container.RegisterAll(typeof(ICommandValidator<>), types);

Here we use the GetTypesToRegister method to find all non-generic implementations, we append the open generic type to this collection and register the whole set using RegisterAll.

Your second option is to mix RegisterManyForOpenGeneric with AppendToCollection:

_container.RegisterManyForOpenGeneric(typeof(ICommandValidator<>), 
    _container.RegisterAll,
    typeof(ICommandValidator<>).Assembly);

// using SimpleInjector.Advanced;
_container.AppendToCollection(typeof(ICommandValidator<>),
    typeof(DataAnnotationsValidator<>));

Upvotes: 2

Related Questions