我试图弄清楚每次从容器中解析实例时如何获得新的生命周期范围。我想这样做,而不需要知道有关Autofac的依赖组件。
我正在创建一个具有"主服务器" (IMasterServer
)组件和零个或多个"会话服务器" (ISessionServer
)组件。主服务器和会话服务器都有自己的IMessageBroker
依赖项。只要主服务器从消息代理获得消息,主服务器就会创建一个新的会话服务器。
问题是每个会话服务器实例都需要自己的IMessageBroker
,我不认为我可以使用InstancePerDependency()
,因为ISessionServer
的其他子组件也需要访问IMessageBroker
所以消息代理需要是会话范围内的单个实例。所以我的想法是,当主服务器产生一个新会话时,它应该在一个新的生命周期内完成,我可以使用IMessageBroker
注册InstancePerLifetimeScope()
依赖项。
所以,问题是,如何将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签名必须包含{ {1}}输入。
到目前为止我所拥有的:
Owned<T>
您可以看到MasterServer具体类需要使用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);
}
}
命名空间才能使用Autofac.Features.OwnedInstances
关系类型定义会话工厂。
每次通过注入Owned<T>
的工厂解决ISessionServer
时,如何使用Autofac创建新的生命周期范围,而组件不需要知道有关正在使用的特定DI容器的任何信息?
答案 0 :(得分:0)
我一直认为让特定于Autofac的代码进入工厂类是两个罪恶。
所以,如果我在你身边,我会使用Owned<T>
课程,称之为一天,继续前进。它是一个出色的解决方案,并且可以像Autofac一样自动处理每个组件的自动化。
请记得在需要时致电Dispose
或您拥有的SessionServer
,否则您将泄露资源。
AFAICT Autofac方法不允许您编写100%DI免费代码。所以你需要在某个地方引用它。
包含Owned<T>
的单一参考似乎是一个非常可接受的权衡。
让我指出您设计中的问题(或您所包含的部分):没有简单的方法将ISessionServer链接到一次性范围。
例如:您公开了一个工厂类,然后SessionServer独立出来。 以这种方式管理范围变得很难。
更简洁的方法是将Disposable用于using语句:
using (var sessionServer = sessionFactory.GetServer())
{
// do something with sessionServer.
}