Autofac con FluentValidation in MVC2
-
29-09-2019 - |
Domanda
Ricevo un 'errore di non registrato' durante l'esecuzione nella chiamata ValidatorFactory.CreateInstance. Sembra che il tipo viene inviato al metodo è corretto.
Il mio codice di registrazione:
...
builder.RegisterAssemblyTypes(assembly).Where(t => t.Name.EndsWith("Validator")).As<IValidator>();
builder.Register(d => _containerProvider).As<IContainerProvider>();
builder.Register(d => new ValidatorFactory(_containerProvider.ApplicationContainer.Resolve<IContainerProvider>())).As<IValidatorFactory>();
_containerProvider = new ContainerProvider(builder.Build());
Codice mio ValidatorFactory:
public class ValidatorFactory : ValidatorFactoryBase {
private readonly IContainerProvider _containerProvider;
public ValidatorFactory(IContainerProvider containerProvider) {
_containerProvider = containerProvider;
}
public override IValidator CreateInstance(Type validatorType) {
return _containerProvider.ApplicationContainer.Resolve<IValidator>(validatorType);
}
}
La mia vista del modello e validatore di codice:
[Validator(typeof(EmployeeViewModelValidator))]
public class EmployeeViewModel {
public EmployeeViewModel() {}
public EmployeeViewModel(string firstName) {
FirstName = firstName;
}
public string FirstName { get; private set; }
}
public class EmployeeViewModelValidator : AbstractValidator<EmployeeViewModel> {
public EmployeeViewModelValidator() {
RuleFor(x => x.FirstName)
.NotEmpty();
}
}
La mia ipotesi migliore è che sto registrando il torto validatori.
Soluzione 3
Registrazione attuale Codice:
builder.RegisterType<EmployeeViewModelValidator>().Keyed<IValidator>(typeof(EmployeeViewModel));
builder.RegisterType<ValidatorFactory>().As<IValidatorFactory>();
_containerProvider = new ContainerProvider(builder.Build());
attuale ValidatorFactory:
public class ValidatorFactory : ValidatorFactoryBase {
readonly IIndex<Type, IValidator> _validators;
public ValidatorFactory(IIndex<Type, IValidator> validators) {
_validators = validators;
}
public override IValidator CreateInstance(Type validatorType) {
return _validators[validatorType];
}
}
Lo stesso errore all'interno CreateInstance:
Il servizio richiesto 'FluentValidation.IValidator`1 [.EmployeeViewModel] (FluentValidation.IValidator)' non è stato registrato.
Altri suggerimenti
Per risolvere da più classi che implementano IValidator
, spettacoli il autofac documentazione un paio di tecniche. Non credo che è possibile utilizzare il montaggio con la scansione di questi metodi; avrete registrare i validatori singolarmente.
Per nome
builder.RegisterType<EmployeeViewModelValidator>().Named<IValidator>("employee");
var r = container.Resolve<IValidator>("employee");
Per chiave
Gli spettacoli di documentazione un'enumerazione utilizzati come una chiave, ma è possibile utilizzare il tipo come la chiave, che avrebbe permesso di chiamare Resolve
utilizzando il validatorType
essere passato a voi nel metodo CreateInstance
.
builder.RegisterType<EmployeeViewModelValidator>().Keyed<IValidator>(typeof(EmployeeViewModelValidator));
var r = container.Resolve<IValidator>(validatorType);
Nota: La documentazione è per la versione 2.3 di Autofac. Sto utilizzando 2.2.4, che è il motivo per cui i nomi dei metodi sopra variano dalla documentazione.
Spero che questo aiuti.
L'altra risposta da @adrift è un bel approccio pulito. Giusto per aggiungere alcune note, questo funziona anche con il tipo di relazione IIndex<K,V>
, che Autofac fornisce automaticamente, per esempio:.
public class ValidatorFactory : ValidatorFactoryBase {
readonly IIndex<Type, IValidator> _validators;
public ValidatorFactory(IIndex<Type, IValidator> validators) {
_validators = validators;
}
public override IValidator CreateInstance(Type validatorType) {
return _validators[validatorType];
}
}
Nota importante : non utilizzare IContainerProvider
e ApplicationContainer
in un componente-invece uso IComponentContext
o IIndex<K,V>
come sopra. Questo aiuto consentirà di evitare problemi di vita (il vostro esempio associa validatori con l'applicazione, piuttosto che la durata richiesta.)