Классы AbstractValidator всегда являются синглетонами, несмотря на то, что они зарегистрированы как временные

Я использую SimpleInjector 4 и FluentValidation 7. Мой AbstractValidatorу меня есть зависимость от моего DbContext,

public class Validator : AbstractValidator<LocationModel>
{
    public LocationModelValidator(IReadOnlyRepository repository)
    {
        // Check the database to see if this location is already present
        RuleFor(x => x.LocationId).Must(x => !repository.Location.Any(i => i.LocationId == x)).WithMessage("A Location with this ID already exists.");
    }
}

Моя композиция root выглядит следующим образом:

var container = new Container();
container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();

container.Register<IReadOnlyRepository, LocationDbContext>(Lifestyle.Scoped);
container.Register<IValidatorFactory>(() => new ServiceProviderValidatorFactory(GlobalConfiguration.Configuration));
container.Register(typeof(IValidator<>), assemblies, Lifestyle.Scoped);

container.RegisterWebApiControllers(GlobalConfiguration.Configuration);

container.Verify();

GlobalConfiguration.Configuration.DependencyResolver = 
    new SimpleInjectorWebApiDependencyResolver(container);

Реализация ValidatorFactory

public class ServiceProviderValidatorFactory : ValidatorFactoryBase
{
    private readonly HttpConfiguration _config;

    public ServiceProviderValidatorFactory(HttpConfiguration config)
    {
        _config = config;
    }

    public override IValidator CreateInstance(Type validatorType)
    {
        return (IValidator) _config.DependencyResolver.GetService(validatorType);
    }
}

WebApiConfig.cs

// throws error: instance is requested outside the context of an active (Async Scoped) scope
// FluentValidationModelValidatorProvider.Configure(GlobalConfiguration.Configuration, x => x.ValidatorFactory = container.GetInstance<IValidatorFactory>());

FluentValidationModelValidatorProvider.Configure(config, x => x.ValidatorFactory = new ServiceProviderValidatorFactory(config));

Проверка запускается и работает нормально для первого запроса API, но все последующие запросы API дают The operation cannot be completed because the DbContext has been disposed. ошибка.

Я также попытался настроить ServiceProviderValidatorFactory использовать IServiceProvider подход и вызов FluentValidationModelValidatorProvider.Configure(config, x => x.ValidatorFactory = new ServiceProviderValidatorFactory(container));

как показано здесь:

/questions/39322014/simpleinjector-i-fluentvalidationfactory/39322034#39322034

но это тоже не работает.

Похоже, что когда-то AbstractValidatorзагружены, они кэшируются / никогда не удаляются, кроме DbContext является. Я предполагаю, что гибридный образ жизни может работать здесь (как установка IReadOnlyRepository синглтонский образ жизни работает нормально) но мне там тоже не повезло.

ОБНОВИТЬ

Выглядит как будто AbstractValidator классы синглтонов. Я обновил валидаторы и фабрику, чтобы они были временными в корне композиции, но, похоже, это не работает, так как они все еще создаются только один раз.

container.Register<IValidatorFactory>(() => new ServiceProviderValidatorFactory(container), Lifestyle.Scoped);
container.Register(typeof(IValidator<>), assemblies, Lifestyle.Transient);

Я подтвердил это, установив точку останова внутри одного моего AbstractValidator классы и может видеть, что он вызывается только один раз, то есть при первом запросе веб-API, но не при последующих запросах.

ОБНОВЛЕНИЕ 2

Я смог несколько обойти эту проблему, введя Func<IReadOnlyRepository> repository в мой AbstractValidator классы:

public class LocationModelValidator : AbstractValidator<LocationModel>
{
    public LocationModelValidator(Func<IReadOnlyRepository> repository)
    {
        // Check the database to see if this location is already present
        RuleFor(x => x.LocationId).Must(x => !repository.Invoke().Locations.Any(i => i.LocationId == x)).WithMessage("A Location with this ID already exists.");
    }
}

И обновляю мою композицию root следующим:

container.RegisterSingleton<Func<IReadOnlyRepository>>(() => container.GetInstance<IReadOnlyRepository>);

Я бы предпочел не делать этого, но, учитывая, что я не могу понять, почему AbstractValidatorЭто всегда одиночки, это будет делать пока.

0 ответов

Другие вопросы по тегам