I want to create a field validator factory using autofac's built in IIndex<TKey, TValue> that will take in an enum value and return me an IFieldValidator. My validation factory should either return a concrete implementation of FieldValidator or ConditionalFieldValidator based upon a supplied token type enum value.
Service
User
Candidate
Unknown
I want to return a ConditionalFieldValidator when the token type is Service
and I want to return a FieldValidator when the token type is either User, Candidate or Unknown
It appears that ContainerBuilder's Keyed method only accepts one parameter which forces me to register the components like this:
builder.RegisterType<ConditionalFieldValidator>().Keyed<IFieldValidator>(TokenType.Service);
builder.RegisterType<FieldValidator>().Keyed<IFieldValidator>(TokenType.User);
builder.RegisterType<FieldValidator>().Keyed<IFieldValidator>(TokenType.Candidate);
builder.RegisterType<FieldValidator>().Keyed<IFieldValidator>(TokenType.Unknown);
Is there a better way to do this that doesn't duplicate the FieldValidator registration? Would be nice to be able to pass multiple token types to the Keyed method.
I ended up creating an extension method that incorporates Alistair and Cyril's answers.
public static ContainerBuilder RegisterTypeKeyed<TConcrete, TAbstract>(this ContainerBuilder containerBuilder, params object[] values)
{
var registration = containerBuilder.RegisterType<TConcrete>();
foreach(var value in values)
registration.Keyed<TAbstract>(value);
return containerBuilder;
}
This allows you to register your keyed components in one line from your container factory.
builder.RegisterTypeKeyed<ConditionalFieldValidator, IFieldValidator>(AuthTokenType.Service);
builder.RegisterTypeKeyed<FieldValidator, IFieldValidator>(AuthTokenType.Candidate, AuthTokenType.Unknown, AuthTokenType.User);
You should just be able to stack multiple Keyed
calls onto the registration (like you can with As<T>
), like so:
builder.RegisterType<FieldValidator>().Keyed<IFieldValidator>(TokenType.User)
.Keyed<IFieldValidator>(TokenType.Candidate)
.Keyed<IFieldValidator>(TokenType.Unknown);
That keeps the same registration of the FieldValidator
component (including any instance sharing behaviour), but registers multiple services.