Autofac:即时为每个实例创建嵌套范围
Autofac: creating nested scopes per instance on-the-fly
我想为用户创建的每个项目实现一个应用程序范围的容器和一个(嵌套的)容器。我查看了 Owned<T>
,但后来——据我所知——我的内部项目集合必须是 <Owned<Project>>
,这是我不想要的,而且我也未能将项目依赖项注入到项目范围内使用的对象 ("circular component dependency")。我考虑过在项目工厂中使用新的 ContainerBuilder,但是缺少 "nested" 方面。
我想要 类 的一些示例(带有依赖项):
- 在全球范围内:
ProjectManager(IProjectFactory)
- 在每个项目的范围内:
Project(IDocumentFactory documentFactory)
、Document(IProject project, IProjectSettings settings)
。
因此,对于项目的范围,我会注册 IDocumentFactory
、IProjectSettings
(以及项目本身?)。
当一个项目 closed/disposed 时,所有创建的依赖项当然也应该被释放。
如果可能,具体 类(ProjectFactory 除外)应该是 Autofac 不可知的。
仅供参考:该应用程序是使用 C# 和 Autofac 4.8 的桌面应用程序。
谢谢!
更新:感谢您的评论,讨论帮助我找到了自己的观点。目前我在我的 ProjectFactory
:
中设置了这样的东西
public Project Create()
{
var scope = _globalScope.BeginLifetimeScope(MyIocHelper.RegisterProjectDependencies);
var p = scope.Resolve<Project>();
_projectScopes.Add(p, scope);
p.Disposing += project_Disposing;
return p;
}
注意事项:
- 据我所知,没有必要在生命周期范围内使用标签。
Project
在第一次调用其 Dispose
方法时引发 Disposing
事件。
- 工厂留着一个
Dictionary<Project, ILifetimeScope>
,项目处置时清理
您可以通过命名生命周期范围和每个生命周期实例范围注册的组合来完成您正在寻找的东西。
此处的文档:http://autofac.readthedocs.io/en/latest/lifetime/working-with-scopes.html#tagging-a-lifetime-scope
您需要:
- 将您的 ProjectManager 注册为 SingleInstance
将项目注册为:
builder.Register<Project>()
.As<IProject>()
.InstancePerMatchingLifetimeScope("project");
这将保证每个标记为 "project".
的范围可以解决一次项目(例如通过文档)
在 ProjectManager 中实现一个 OpenProject(或其他)方法。此方法应实例化标记为 "project" 的 LifetimeScope,在其中注册 IDocumentFactory
、IProjectSettings
,以便每个项目范围仅解析一次,并将范围本身附加到 Project 实例. 这个很关键: 销毁项目的时候需要销毁作用域
public class ProjectManager : IProjectFactory
{
private readonly ILifetimeScope _scope;
public ProjectManager(ILifetimeScope scope)
{
// this is going to be the global scope.
_scope = scope;
}
public Project OpenProject(IDocumentFactory docFactory, IProjectSettings settings)
{
var projectScope = _scope.BeginLifetimeScope("project");
projectScope.RegisterInstance(docFactory).AsImplementedInterfaces();
projectScope.RegisterInstance(settings).AsImplementedInterfaces();
return projectScope.Resolve<Project>();
}
}
public class ProjectScope : IDisposable
{
private readonly ILifetimeScope _scope;
public ProjectManager(ILifetimeScope scope)
{
// this is going to be the project scope.
_scope = scope;
}
public void Dispose() {
if (_scope != null) {
_scope.Dispose();
_scope = null;
}
}
}
public class Project : IDisposable
{
private readonly ProjectScope _scope;
public Project(ProjectScope scope /*, ...*/)
{
_scope = scope;
}
public void Dispose() {
// pay attention that this method will be called 2 times, once by you
// and another time by the underlying LifetimeScope. So this code should
// handle that gracefully (so the _scope == null).
if (_scope != null) {
_scope.Dispose();
_scope = null;
}
}
}
考虑到所有这些,您将每个 using Autofac
保留在每个 class 之外,除了全局管理器和 ProjectScope 的 2 个例外。如果您在 Project
class 本身中接受单个 using Autofac
,则可以更改有关范围处理方式的一些位:您可以直接获取 ILifetimeScope
并处理它直接。
希望对您有所帮助!
我想为用户创建的每个项目实现一个应用程序范围的容器和一个(嵌套的)容器。我查看了 Owned<T>
,但后来——据我所知——我的内部项目集合必须是 <Owned<Project>>
,这是我不想要的,而且我也未能将项目依赖项注入到项目范围内使用的对象 ("circular component dependency")。我考虑过在项目工厂中使用新的 ContainerBuilder,但是缺少 "nested" 方面。
我想要 类 的一些示例(带有依赖项):
- 在全球范围内:
ProjectManager(IProjectFactory)
- 在每个项目的范围内:
Project(IDocumentFactory documentFactory)
、Document(IProject project, IProjectSettings settings)
。
因此,对于项目的范围,我会注册 IDocumentFactory
、IProjectSettings
(以及项目本身?)。
当一个项目 closed/disposed 时,所有创建的依赖项当然也应该被释放。
如果可能,具体 类(ProjectFactory 除外)应该是 Autofac 不可知的。
仅供参考:该应用程序是使用 C# 和 Autofac 4.8 的桌面应用程序。
谢谢!
更新:感谢您的评论,讨论帮助我找到了自己的观点。目前我在我的 ProjectFactory
:
public Project Create()
{
var scope = _globalScope.BeginLifetimeScope(MyIocHelper.RegisterProjectDependencies);
var p = scope.Resolve<Project>();
_projectScopes.Add(p, scope);
p.Disposing += project_Disposing;
return p;
}
注意事项:
- 据我所知,没有必要在生命周期范围内使用标签。
Project
在第一次调用其Dispose
方法时引发Disposing
事件。- 工厂留着一个
Dictionary<Project, ILifetimeScope>
,项目处置时清理
您可以通过命名生命周期范围和每个生命周期实例范围注册的组合来完成您正在寻找的东西。
此处的文档:http://autofac.readthedocs.io/en/latest/lifetime/working-with-scopes.html#tagging-a-lifetime-scope
您需要:
- 将您的 ProjectManager 注册为 SingleInstance
将项目注册为:
builder.Register<Project>() .As<IProject>() .InstancePerMatchingLifetimeScope("project");
这将保证每个标记为 "project".
的范围可以解决一次项目(例如通过文档)
在 ProjectManager 中实现一个 OpenProject(或其他)方法。此方法应实例化标记为 "project" 的 LifetimeScope,在其中注册
IDocumentFactory
、IProjectSettings
,以便每个项目范围仅解析一次,并将范围本身附加到 Project 实例. 这个很关键: 销毁项目的时候需要销毁作用域public class ProjectManager : IProjectFactory { private readonly ILifetimeScope _scope; public ProjectManager(ILifetimeScope scope) { // this is going to be the global scope. _scope = scope; } public Project OpenProject(IDocumentFactory docFactory, IProjectSettings settings) { var projectScope = _scope.BeginLifetimeScope("project"); projectScope.RegisterInstance(docFactory).AsImplementedInterfaces(); projectScope.RegisterInstance(settings).AsImplementedInterfaces(); return projectScope.Resolve<Project>(); } } public class ProjectScope : IDisposable { private readonly ILifetimeScope _scope; public ProjectManager(ILifetimeScope scope) { // this is going to be the project scope. _scope = scope; } public void Dispose() { if (_scope != null) { _scope.Dispose(); _scope = null; } } } public class Project : IDisposable { private readonly ProjectScope _scope; public Project(ProjectScope scope /*, ...*/) { _scope = scope; } public void Dispose() { // pay attention that this method will be called 2 times, once by you // and another time by the underlying LifetimeScope. So this code should // handle that gracefully (so the _scope == null). if (_scope != null) { _scope.Dispose(); _scope = null; } } }
考虑到所有这些,您将每个 using Autofac
保留在每个 class 之外,除了全局管理器和 ProjectScope 的 2 个例外。如果您在 Project
class 本身中接受单个 using Autofac
,则可以更改有关范围处理方式的一些位:您可以直接获取 ILifetimeScope
并处理它直接。
希望对您有所帮助!