【问题标题】:Autofac/FluentValidation: No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requestedAutofac/FluentValidation:从请求实例的范围内看不到标签匹配“AutofacWebRequest”的范围
【发布时间】:2015-12-08 00:02:58
【问题描述】:

尝试将数据注入 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);

    }
}

得到以下异常:

从请求实例的范围中看不到带有与“AutofacWebRequest”匹配的标记的范围。这通常表明注册为 per-HTTP 请求的组件正在由 SingleInstance() 组件(或类似场景)请求。在 Web 集成下,始终从 DependencyResolver.Current 或 ILifetimeScopeProvider.RequestLifetime 请求依赖项,而不是从容器本身.

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

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

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

【问题讨论】:

  • 你能显示你调用验证器实例解析的地方吗?

标签: c# dependency-injection autofac fluentvalidation


【解决方案1】:

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

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

因此,我们已经确定您的 MyFormValidator 没有从“请求”范围解析。为什么?

您编写的自定义DependencyResolverValidatorFactory 采用由Autofac 构建的实际IContainer,并从中解决。这是ILifetimeScope 的一种特殊类型,即“根范围”。没有与此直接关联的请求生命周期范围,因此您会遇到异常。您需要从“请求”范围或请求范围内包含的子范围开始的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())进行注册,具体取决于验证器如何/是否可以或应该共享。

祝你好运。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-01-11
    • 1970-01-01
    • 2021-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-21
    相关资源
    最近更新 更多