【问题标题】:Implicit scope on resolve without using Autofac namespace不使用 Autofac 命名空间的隐式解析范围
【发布时间】:2017-06-11 19:06:06
【问题描述】:

我试图弄清楚每次我从容器中解析一个实例时如何获得一个新的生命周期范围。我想在不需要了解 Autofac 的依赖组件的情况下执行此操作。

我正在创建一个 .NET Core 服务器应用程序(控制台应用程序),它有一个“主服务器”(IMasterServer)组件和零个或多个“会话服务器”(ISessionServer)组件。主服务器和会话服务器都有自己的 IMessageBroker 依赖项。每当主服务器从消息代理收到消息时,它都会创建一个新的会话服务器。

问题是每个会话服务器实例都需要自己的IMessageBroker,我认为我不能使用InstancePerDependency(),因为ISessionServer 的其他子组件也需要访问IMessageBroker,所以消息代理需要是会话范围内的单个实例。所以我的想法是,当主服务器产生一个新会话时,它应该在新的生命周期内这样做,我可以使用 InstancePerLifetimeScope() 注册 IMessageBroker 依赖项。

所以,问题是,我如何将ISessionServer 工厂注入IMasterServer,这样每次调用该工厂时,都会为生成的ISessionServer 实例创建一个新的生命周期范围?以及如何做到这一点,使得所有组件都不需要了解 Autofac?

这两个 SO 问题都建议使用Owned<T> 关系:

Can I create an implicit Lifetime scope within a factory?

Is it possible to create a new scope whenever a component is resolved?

但是,除非我遗漏了什么,否则这意味着将要注入依赖项的组件(在我的例子中为 IMasterServer)需要了解 Autofac,因为它的 ctor 签名必须包含 Owned<T> 类型。

到目前为止我所拥有的:

using Autofac.Features.OwnedInstances;

class MasterServer : IMasterServer
{
    private IMessageBroker mMessageBroker;
    private Func<Owned<ISessionServer>> mSessionServerFactory;

    public Master(
        Func<string, IServerMessageBroker> messageBrokerFactory,
        Func<Owned<ISessionServer>> sessionServerFactory
    )
    {
        mMessageBroker = messageBrokerFactory("master");
        mSessionServerFactory = sessionServerFactory;
    }
}


class SessionServer : ISessionServer
{
    private IMessageBroker mMessageBroker;
    private string mId;

    public SessionServer(
        Func<string, IMessageBroker> messageBrokerFactory
    )
    {
        mId = Guid.NewGuid().ToString();
        mMessageBroker = messageBrokerFactory(mId);
    }
}

您可以看到,MasterServer 具体类需要使用Autofac.Features.OwnedInstances 命名空间才能使用Owned&lt;T&gt; 关系类型定义会话工厂。

每次通过注入MasterServer 的工厂解析ISessionServer 时,我如何使用Autofac 创建一个新的生命周期范围,而不需要组件了解有关正在使用的特定DI 容器的任何信息?

【问题讨论】:

    标签: c# autofac


    【解决方案1】:

    我一直觉得让 Autofac 特定的代码滑入工厂类是两害相权取其轻。 所以,如果我在你身边,我会使用 Owned&lt;T&gt; 课程,收工并继续前进。这是一个很好的解决方案,可以像 Autofac 一样让每个组件的所有处理都自动进行。

    记得在需要的时候拨打Dispose或者你自己的SessionServer,否则你会泄露资源。

    AFAICT Autofac 方法不允许您编写 100% 无 DI 的代码。所以你需要在某个地方引用它。

    包含Owned&lt;T&gt; 的单个引用似乎是一个可以接受的折衷方案。

    让我指出您的设计(或您包含的部分)中的一个问题:没有简单的方法可以将 ISessionServer 链接到一次性作用域。

    例如:你暴露了一个工厂类,然后 SessionServer 自己出来了。 以这种方式管理范围变得很困难。

    更简洁的方法是在 using 语句中使用 Disposable:

    using (var sessionServer = sessionFactory.GetServer())
    {
        // do something with sessionServer.
    }
    

    【讨论】:

    • 感谢您的意见。随着我继续开发这个应用程序,我看到在其他地方实现有价值的 Autofac 功能将导致我的更多组件需要了解 Autofac。我想我应该按照你的建议接受它。
    • 关于您将 SessionServer 包装在 using 块中的建议,我认为我不能这样做,因为 MasterServer 需要挂在 SessionServer 实例的集合上。它会在 Disposed 时处理掉它们。
    • 我建议您在特定位置保留 Autofac 的使用。例如,您可以创建一个类SessionServerHandle 实现getSessionServer() 方法,并负责创建特定的Autofac 范围、实例化和处置SessionServer 实例。简而言之,一个负责管理工作单元的类。
    • 我的经验法则是实现类应该是免费的 Autofac。像工厂这样的特殊类是我让 DI 代码进入实现的一个地方。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多