Skip to main content
 首页 » 编程设计

c#之Autofac/流利验证 : No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested

2024年01月31日24langtianya

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

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

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

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

请您参考如下方法:

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

您遇到的异常意味着 Autofac 无法将您的服务解析为“每个请求的实例”。在 Autofac documentation 上有很多关于这意味着什么的文档。页。总而言之,这意味着 Autofac 将尝试从为每个发送到网络服务器的请求自动创建的生命周期范围内解析服务。当您将某些内容注册为 .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)); 

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

祝你好运。