Autofac/FluentValidation:从请求实例的范围内看不到标签匹配 'AutofacWebRequest' 的范围

Autofac/FluentValidation: No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested

正在尝试将数据注入 FluentValidation 验证器:

public class MyFormValidator : AbstractValidator<MyForm>
{
    private readonly IQueryable<Models.User> _users;

    public MyFormValidator(IQueryable<Models.User> users)
    {
        _users = users;
        ...
    }
}

我的验证器工厂:

public class DependencyResolverValidatorFactory : ValidatorFactoryBase
{
    private readonly IContainer container;

    public DependencyResolverValidatorFactory(IContainer container)
    {
        this.container = container;
    }

    public override IValidator CreateInstance(Type validatorType)
    {
        return container.ResolveOptionalKeyed<IValidator>(validatorType);
    }
}

我的 Autofac 配置器:

public class AutofacConfigurator
{
    public static void Configure()
    {
        var builder = new ContainerBuilder();
        ...

        builder.RegisterType<MyFormValidator>()
            .Keyed<IValidator>(typeof(IValidator<MyForm>))
            .As<IValidator>()
             // 2nd parameter returns IQueryable<User>
            .WithParameter("users", new SqlRepository<User>(dataContext)) 
            .InstancePerRequest();

        builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource());

        var container = builder.Build();

        DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

        // Register the validator factory with FluentValidation, and register 
        // FluentValidation as the model validator provider for the MVC framework. 
        // see http://www.jerriepelser.com/blog/using-fluent-validation-with-asp-net-mvc-part-3-adding-dependency-injection
        var fluentValidationModelValidatorProvider = 
            new FluentValidationModelValidatorProvider(
                new DependencyResolverValidatorFactory(container));
        DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
        fluentValidationModelValidatorProvider.AddImplicitRequiredValidator = false;
        ModelValidatorProviders.Providers.Add(fluentValidationModelValidatorProvider);

    }
}

得到以下异常:

No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested. This generally indicates that a component registered as per-HTTP request is being requested by a SingleInstance() component (or a similar scenario.) Under the web integration always request dependencies from the DependencyResolver.Current or ILifetimeScopeProvider.RequestLifetime, never from the container itself.

我还有其他验证器,其中大部分不需要向其中注入数据。

这对我来说(在 Autofac 和 FluentValidation 中)很大程度上是新领域,并且我仍在努力理解我在这里所做的事情。我怀疑我只是错误地注册了我的类型。我该如何解决这个问题并正确注册我的类型?

(如果这与已经提出的其他问题太相似,我深表歉意。)

我对 FluentValidation 的经验为零,但我怀疑这无论如何都是你问题的原因,所以无论如何我都会继续努力。

您遇到的异常意味着 Autofac 无法将您的服务解析为 'instance per request'。在 Autofac documentation 页面上有很多关于这意味着什么的文档。总而言之,这意味着 Autofac 将尝试从为每个发送到网络服务器的请求自动创建的生命周期范围内解析服务。当您将某些内容注册为 .InstancePerRequestScope() 但随后尝试在该范围之外解析该服务时,您将得到您看到的 DependencyResolutionException

因此我们确定您的 MyFormValidator 不是从 'Request' 范围解析的。为什么?

您编写的自定义 DependencyResolverValidatorFactory 采用由 Autofac 构建的实际 IContainer,并从中解析。这是一个特殊的类型ILifetimeScope,'root scope'。没有与此直接关联的请求生命周期范围,因此您会遇到异常。您需要从 'request' 范围或包含在请求范围内的子范围开始的 ILifetimeScope 进行解析。

Autofac/MVC 集成已经自动托管请求范围(在 AutofacDependencyResolver 内,请参阅 the source),但您的自定义 DependencyResolverValidatorFactory 无法从中解析。如果您想这样做,我想您可以修改 DependencyResolverValidatorFactory 以接受 AutofacDependencyResolver 实例,并使用它来解析。

看起来像这样:

public class DependencyResolverValidatorFactory : ValidatorFactoryBase
{
    private readonly AutofacDependencyResolver resolver;

    public DependencyResolverValidatorFactory(AutofacDependencyResolver resolver)
    {
        this.resolver = resolver;
    }

    public override IValidator CreateInstance(Type validatorType)
    {
        return resolver.RequestLiftimeScope.ResolveOptionalKeyed<IValidator>(validatorType);
    }
}

请注意 RequestLifetimeScope 卡在那里。 然后在 .Configure() 方法中使用

创建它
var resolver = new AutofacDependencyResolver(container);
DependencyResolver.SetResolver(resolver);

var fluentValidationModelValidatorProvider = 
    new FluentValidationModelValidatorProvider(
        new DependencyResolverValidatorFactory(resolver));

假设这个工厂在创建 IValidators 的实例时确实有一个工作请求,那应该消除异常。如果没有,您可能需要使用默认行为(.InstancePerDependency(),每次请求时都会创建一个新实例)或单例(.SingleInstance())进行注册,具体取决于 how/if 验证器可以或者应该分享。

祝你好运。