Autofac:即时为每个实例创建嵌套作用域

时间:2018-04-30 14:45:08

标签: c# autofac ioc-container

我想为用户创建的每个项目实现一个应用程序范围的容器和一个(嵌套的)容器。我调查了Owned<T>,然后 - 据我所知 - 我的内部项目集合必须是<Owned<Project>>我不想要的,而且我也没有注入项目依赖项项目范围内使用的对象(&#34;循环组件依赖&#34;)。我考虑过在项目工厂中使用一个新的ContainerBuilder,然后是#34;嵌套&#34;缺少方面。

我希望有一些类(带有依赖项)的exapmles:

  • 在全球范围内:ProjectManager(IProjectFactory)
  • 在每个项目的范围内:Project(IDocumentFactory documentFactory)Document(IProject project, IProjectSettings settings)

因此,对于项目的范围,我会注册IDocumentFactoryIProjectSettings(以及项目本身?)。

当项目关闭/处置时,当然也应该处理所有创建的依赖项。

如果可能,具体类(ProjectFactory除外)应该是Autofac-agnostic。

仅供参考:应用程序是使用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在第一次调用Disposing方法时引发Dispose事件。
  • 工厂保留Dictionary<Project, ILifetimeScope>并在项目处理时清理它。

1 个答案:

答案 0 :(得分:1)

您可以结合使用命名的生命周期范围和每个生命周期范围的实例注册来完成您要查找的内容。

此处的文档:http://autofac.readthedocs.io/en/latest/lifetime/working-with-scopes.html#tagging-a-lifetime-scope

你需要:

  1. 将ProjectManager注册为SingleInstance
  2. 将项目注册为:

         builder.Register<Project>()
            .As<IProject>()
            .InstancePerMatchingLifetimeScope("project");
    

    这将保证每个标记为“项目”的范围可以解决一个项目(例如通过文档)。

  3. 在ProjectManager中实现OpenProject(或其他)方法。此方法应实例化标记为“项目”的LifetimeScope,在其中注册IDocumentFactoryIProjectSettings,因此它们仅针对每个项目范围解析一次,并将范围本身附加到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;
            }
        }
    }
    
  4. 考虑到所有这些,你可以保留每个类中的每个using Autofac,除了全局管理器和ProjectScope之外的两个例外。如果您在using Autofac类中接受一个Project,则可以更改有关范围处理方式的一些内容:您可以直接获取ILifetimeScope并直接处理它。

    希望这有帮助!