【问题标题】:Autofac - how to resolve Func for ISomething from Singleton where ISomething is InstancePerHttpRequestAutofac - 如何从单例中解析 ISomething 的 Func,其中 ISomething 是 InstancePerHttpRequest
【发布时间】:2013-03-21 02:56:54
【问题描述】:

我正在尝试使用 Autofac 将依赖项注入到 MVC 4 应用程序中的 FluentValidation 中。我想我已经制定了策略,但我无法解决我的每个请求 ISomething 从一个单身人士。

这是场景: 我有一个从 FluentValidation 的 AbstractValidator 派生的验证器。我读过 FluentValidation 验证器作为单例执行得最好,所以我的构造函数需要一个 Func 并存储该 Factory 以供以后使用。使用验证器时,它应该向存储的工厂请求 IDataStore,获取为该请求创建的实例并使用它。这就是理论。我想感谢https://github.com/robdmoore/UnobtrusiveMVCTechniques,它帮助我确定了这个解决方案。这是验证器...

public class SiteAdminViewModelValidator : AbstractValidator<SiteAdminViewModel> {
    private readonly Func<IDataStore> _dbFactory;

    public SiteAdminViewModelValidator(Func<IDataStore> dbFactory) {
        _dbFactory = dbFactory;

        RuleFor(model => model.SiteCode).Length(1, 40).Must(BeSpecial);
    }

    public bool BeSpecial(string siteCode) {
        var db = _dbFactory();
        List<Stuff> stuffs = db.All<Stuff>().ToList();

        return true;
    }
}

如果有人能指出我正在努力完成的工作示例,那就太好了,但我也想知道 Autofac 这种特殊技巧的解决方案。

这是我的验证器注册...

public class FluentValidatorModule : Module {
    protected override void Load(ContainerBuilder builder) {
        base.Load(builder);
        builder.RegisterType<AutofacValidatorFactory>().As<IValidatorFactory>().SingleInstance();

    var validators = AssemblyScanner.FindValidatorsInAssembly(System.Reflection.Assembly.GetExecutingAssembly());
    validators.ToList().ForEach(v => builder.RegisterType(v.ValidatorType).As(v.InterfaceType).SingleInstance());
    }
}

这是我对 IDataStore 工厂的注册...

builder.RegisterType<SuperDB>().As<IDataStore>().InstancePerHttpRequest();
builder.Register<Func<IDataStore>>(c => {
                                       var context = c.Resolve<IComponentContext>();
                                       return context.Resolve<IDataStore>;
                                   });

这是当我的验证器在线请求 IDataStore 时出现的错误 - var db = _dbFactory();

标签匹配“AutofacWebRequest”的范围不可见 请求实例的范围。这通常表明 正在请求注册为 per-HTTP 请求的组件 一个 SingleInstance() 组件(或类似的场景)。在 web 下 集成总是从 DependencyResolver.Current 或 ILifetimeScopeProvider.RequestLifetime, 永远不要来自容器本身。

...这正是我在编写自己的工厂注册(Func 注册)之前尝试过的结果。通过阅读类似问题的各种答案,我上面的内容看起来应该可以工作,因为我认为我现在正在解析 Func 以获得当前的解析器。

任何帮助将不胜感激。

【问题讨论】:

    标签: inversion-of-control autofac fluentvalidation


    【解决方案1】:

    我同意这应该可行 - Func&lt;IDataStore&gt; 正在定义一个工厂,它将根据需要在每个方法中生成依赖项。

    我绕过这种方法的方法是使用DependencyResolver.Current,就像错误消息所暗示的那样。主要原因是我已经使用 Autofac.Mvc4 nuget 包进行了设置...

    DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
    

    所以要实际设置方法,我有以下函数

    public Func<T> PerHttpSafeResolve<T>()
    {
        return () => DependencyResolver.Current.GetService<T>();
    } 
    

    以及在构建容器时

    builder.RegisterType<SuperDB>().As<IDataStore>().InstancePerHttpRequest();
    builder.RegisterInstance(PerHttpSafeResolve<IDataStore>());
    

    编辑:注册实例的第二行是说 - 如果您需要 Func&lt;IDataStore&gt; 然后使用传递给方法的值。 PerHttpSafeResolve&lt;IDataStore&gt; 的结果只是一个函数(工厂),因此它可以作为单个实例存在。

    【讨论】:

    • 这行得通!谢谢。我是 Autofac 的新手。我可以简单说明一下 builder.RegisterInstance(PerHttpSafeResolve[IDataStore]()); 的注册吗?线?也就是说,“每当有人要求 Func[IDataStore] 时,就用这个方法给他们一个”?
    • 很好!!这技术太棒了。我喜欢它。这么多,我写了一篇博文:robdmoore.id.au/blog/2013/03/23/…。如果您自己有博客,请告诉我,我会链接到它而不是您的 SO 用户。
    • 太棒了 :) 我有点失望 Autofac 不能自动执行此操作...但是是的,这是一个相当整洁的 hack :p 链接到我的 SO 用户很好。
    • 什么是 webapi 的等价物?
    • 如果您指定 public Func&lt;T&gt; PerHttpSafeResolve 定义的去向,对于没有经验的人来说会更清楚!
    【解决方案2】:

    问题在于验证器的范围。 Autofac 总是从应用容器解析SingleInstance 依赖,这意味着验证器的依赖也来自应用容器。

    Autofac 正在从 那里 请求 Func&lt;IDataStore&gt; 实例,而不是从请求容器。当您解析 IComponentContext 时,您将获得正在解析验证器的容器:应用程序容器。由于Func&lt;IDataStore&gt; 的作用域是请求,Autofac 无法在应用程序级别提供它,因此会出现错误。

    正确的方法是将验证器注册为InstancePerHttpRequest。组件的生命周期取决于其最长生命周期的依赖关系;当验证器没有依赖关系时,它们作为单例的效果最好。但是,在这种情况下,依赖于 IDataStore 的验证器被限制为最多只能在 IDataStore 实例的生命周期内存活。 (从好的方面来说,你可以摆脱Func。)

    把它想象成去参加一个聚会:如果你和主人搭便车,你必须待在那里直到聚会结束。想早退的不能跟房东搭车。

    【讨论】:

    • 这有助于我了解发生了什么。我想这就是 Felix 的解决方案有效而我的解决方案无效的原因。他明确使用 DependencyResolver.Current,而我只是使用 c.Resolve。我真的很想避免让验证器的构建频率超过绝对必要的频率。由于我可以使用单例解决方案,因此我将走那条路。
    • @TimHardy:很高兴听到这个消息。不要忘记对有帮助的答案投赞成票:-)
    猜你喜欢
    • 1970-01-01
    • 2013-10-06
    • 1970-01-01
    • 1970-01-01
    • 2018-04-29
    • 2011-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多