尽管已注册为暂态类,但AbstractValidator类始终为单例

Cat*_*mas 5 c# asp.net fluentvalidation simple-injector

我正在使用SimpleInjector 4和FluentValidation7。我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.");
    }
}
Run Code Online (Sandbox Code Playgroud)

我的合成根看起来如下:

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);
Run Code Online (Sandbox Code Playgroud)

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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));
Run Code Online (Sandbox Code Playgroud)

验证开始并且对第一个API请求运行正常,但所有后续API请求均给出The operation cannot be completed because the DbContext has been disposed.错误。

我也尝试设置ServiceProviderValidatorFactory使用IServiceProvider方法并调用FluentValidationModelValidatorProvider.Configure(config, x => x.ValidatorFactory = new ServiceProviderValidatorFactory(container));

如下所示:

/sf/answers/3071841881/

但这也不起作用。

看起来,一旦AbstractValidators被加载,它们就被缓存/从不丢弃,但是DbContext是。我猜测混合生活方式可能在这里可行(因为将IReadOnlyRepository单身生活方式设置为正常),但是我也没有任何运气。

更新

看起来这些AbstractValidator类是Singletons。我已经将验证器和工厂更新为在合成根目录中是瞬态的,但由于它们仍仅被实例化一次,因此似乎不起作用。

container.Register<IValidatorFactory>(() => new ServiceProviderValidatorFactory(container), Lifestyle.Scoped);
container.Register(typeof(IValidator<>), assemblies, Lifestyle.Transient);
Run Code Online (Sandbox Code Playgroud)

我已经通过在我的AbstractValidator班级中设置一个断点来验证了这一点,并且可以看到它仅被调用一次,即在第一个Web api请求上被调用,而在随后的请求上未被调用。

更新2

通过将a 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.");
    }
}
Run Code Online (Sandbox Code Playgroud)

并使用以下命令更新我的合成根:

container.RegisterSingleton<Func<IReadOnlyRepository>>(() => container.GetInstance<IReadOnlyRepository>);
Run Code Online (Sandbox Code Playgroud)

我宁愿不必这样做,但是鉴于我无法弄清楚为什么AbstractValidators总是单例,它现在就可以了。