【问题标题】:Singleton with per-transaction Func<> dependency using Autofac使用 Autofac 的具有每个事务 Func<> 依赖项的单例
【发布时间】:2017-08-02 07:53:55
【问题描述】:

我正在使用 ASP.NET Core。我是 Autofac 的新手。

第三方库 (NLog) 在应用程序的生命周期内使用我的 Foo 对象,因此它实际上变成了单例,我无法更改它。问题是 Foo 有一个作用域依赖,它实际上也变成了一个单例(一个俘虏依赖)。

related question 中,有人告诉我将依赖项更改为Func&lt;Dependency&gt;,以便在每个请求上创建一个新实例。内置容器不支持Func&lt;&gt;,所以我用的是Autofac。

我的类型:

public class Foo
{
    public Foo(Func<IMyContext> contextFactory) { _contextFactory = contextFactory; }
    private readonly Func<IMyContext> _contextFactory;

    public void doSomething() { /* shown below */ }
}

我的Startup

public IServiceProvider ConfigureServices(IServiceCollection services)
{
    services.AddScoped<IMyContext, MyContext>();
    services.AddSingleton<Foo>();
    var builder = new ContainerBuilder();
    builder.Populate(services);
    return new AutofacServiceProvider(builder.Build());
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory log)
{
    var foo = app.ApplicationServices.GetService<Foo>();
    ConfigureNLog(foo);    // effectively becomes a singleton, and I can't change that
    // ...
}

为了在请求期间对此进行测试,我记录了实例的哈希码:

public class Foo
{
    // ...

    public void doSomething()
    {
        using (var context = _contextFactory())
        {
            _logger.log(context.GetHashCode());   // should be unique on each request
        }
    }
}

我希望每个请求都有一个唯一的哈希码,因为依赖项是通过 Func&lt;&gt; 工厂创建的。但他们总是一样的!所以每个请求都是同一个实例。

我该如何解决这个问题?

【问题讨论】:

  • 为我工作:dotnetfiddle.net/YsGywP
  • @CodeCaster 该示例不共享任何远程接近 OP 描述的内容。没有生命周期范围,每个服务都注册为瞬态服务,并且没有捕获应该创建上下文的服务的单个实例。
  • @CodeCaster 您的代码 sn-p 帮助很大。您可以添加为答案以便我接受吗?也感谢你向我介绍了非常酷的 dotnetfiddle。
  • 嗯,我认为@Mickaël 有一点,这个问题与你之前的问题没有太大关系,所以我可以看到他的评论来自哪里 - 我知道这个问题的背景,他没有。随意接受他的回答。 :)
  • @CodeCaster 您的代码可以正常工作,只是我需要将您的 ctor 注入 arg 从 Func&lt;Dependency&gt; 更改为 Func&lt;Owned&lt;Dependency&gt;&gt;。现在它完全按预期工作。我不明白为什么,但是有了那个小模块,你的代码就很好用。

标签: .net asp.net-core autofac


【解决方案1】:

TL;DR;

更改上下文的注册,使其看起来像:

services.AddTransient<IMyContext, MyContext>();

这将在每次Foo 调用Func&lt;IMyContext&gt; 时为您提供一个新的MyContext 实例。在这里每次都很重要,因为这意味着如果在同一个 HTTP 请求期间调用 Func 10 次,将创建 10 个不同的实例。

加长版

也许我读错了,但这是我认为您想要实现的目标:您希望注入到 Foo 中的 Func&lt;IMyContext&gt; 在每个 HTTP 请求中解析为 MyContext 的同一实例。

我认为这是不可能的,也不是 Autofac 特有的问题。

原因是注入到Foo 中的Func&lt;IMyContext&gt; 与根生命周期范围相关——因为Foo 本身是从根容器创建的。这意味着 FooFunc&lt;IMyContext&gt; 都不知道为每个 HTTP 请求创建的潜在嵌套生命周期范围。

您唯一可用的解决方案是在每次容器解析MyContext 时创建一个新实例。

这符合您的要求吗?

【讨论】:

  • 很高兴你让它工作,但我认为提供更多信息会有所帮助。您是如何在 Autofac 容器中注册 MyContext 的?我不太相信在 Autofac 中注册所有内容是它工作的原因。
  • 没有它现在起作用的原因是因为我将注入的 ctor arg 从 Func&lt;IMyContext&gt; 更改为 Func&lt;Owned&lt;IMyContext&gt;&gt;
  • 我很难理解为什么这会改变行为。 Owned 的存在只是为了指示 Autofac 不要跟踪服务,因为您自己负责处理它。我知道你可能不想深入挖掘,因为你已经开始工作了,但是通过添加你当前的注册来更新原始问题可能有助于弄清楚会发生什么。
  • Autofac 作者just confirmed this behavior。所以Func&lt;Owned&lt;Dependency&gt;&gt; 在这种情况下似乎是必要的。这是容器以某种方式解析的“信号”。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多