Ninject: Как получить доступ к корневому объекту NamedScope с завода

В моем приложении я использую Ninject и NamedScopeExtension. Один из объектов глубже в графе объектов нуждается в доступе к корневому объекту, который определил названную область. Мне кажется, что DefinesNamedScope() также не подразумевает InNamedScope() и вместо этого новый корневой объект создается, когда я запрашиваю корень.

Пример:

using System;
using Ninject;
using Ninject.Extensions.NamedScope;
using Ninject.Syntax;

namespace NInjectNamedScope
{
    public interface IScopeRoot
    {
        Guid Guid { get; }
        void DoSomething();
    }

    public interface IFactory
    {
        Guid Guid { get; }
        IOther CreateOther();
    }

    public interface IOther
    {
        void SayHello();
    }

    internal class ScopeRoot : IScopeRoot
    {
        private readonly IFactory m_factory;
        private readonly IResolutionRoot m_kernel;
        public Guid Guid { get; private set; }

        public ScopeRoot(IFactory factory, IResolutionRoot kernel)
        {
            m_factory = factory;
            m_kernel = kernel;
            Guid = Guid.NewGuid();
        }

        public void DoSomething()
        {
            Console.WriteLine("ScopeRoot.DoSomething(): Entering");
            Console.WriteLine("ScopeRoot GUID: {0}", Guid);
            Console.WriteLine("IFactory  GUID: {0}", m_factory.Guid);
            var other = m_factory.CreateOther();
            Console.WriteLine("ScopeRoot.DoSomething(): Other created");
            other.SayHello();
            Console.WriteLine("ScopeRoot.DoSomething(): Exiting");
        }
    }

    internal class Factory : IFactory
    {
        private IResolutionRoot m_kernel;

        public Guid Guid { get; private set; }

        public Factory(IResolutionRoot kernel)
        {
            m_kernel = kernel;
            Guid = Guid.NewGuid();
        }
        public IOther CreateOther()
        {
            return m_kernel.Get<IOther>();
        }
    }

    internal class Other : IOther
    {
        private readonly IScopeRoot m_root;
        private readonly IFactory m_factory;

        public Other(IScopeRoot root, IFactory factory)
        {
            m_root = root;
            m_factory = factory;
        }

        public void SayHello()
        {
            Console.WriteLine("Other.SayHello(): Hello");
            Console.WriteLine("Our IScopeRoot has GUID: {0}", m_root.Guid);
            Console.WriteLine("Our IFactory has GUID:   {0}", m_factory.Guid);
        }
    }

    public class MainClass
    {
        public static void Main(string[] args)
        {
            var kernel = new StandardKernel();

            kernel.Bind<IScopeRoot>().To<ScopeRoot>().DefinesNamedScope("RootScope");
            kernel.Bind<IFactory>().To<Factory>().InNamedScope("RootScope");
            kernel.Bind<IOther>().To<Other>().InNamedScope("RootScope");

            var root = kernel.Get<IScopeRoot>();
            root.DoSomething();

            Console.ReadKey();
        }
    }
}

В этом примере Other получает тот же экземпляр Factory как корень, но новый экземпляр ScopeRoot создается вместо внедрения существующего экземпляра, который определил именованную область.

Как я могу получить доступ к корню именованной области на фабрике? Обратите внимание, что этот пример упрощен. В действительности между корнем области видимости и фабричным методом есть несколько слоев объектов, поэтому я не могу просто передать this на завод.

1 ответ

Решение

Да, вы правы, из коробки Ninject не может сделать .DefinesNamedScope().InNamedScope(), За исключением, может быть, позднего "создания" (фабричного, ленивого), это все равно не сработает, потому что это создаст циклическую зависимость.

Самый простой способ добиться того, чего вы хотите, - создать "корень корня"... ну, всего один класс ActualRoot который связан с DefinesNamedScope() и получает IRootScope вводится, что снова будет связано с .InNamedScope(), Плохая вещь в том, что вам нужно будет ввести /Get<> ActualRoot вместо IRootScope,

Насколько я помню, вы также можете сделать следующее:

Bind<IRootScope>().To<RootScope>()
    .InNamedScope(scopeName);

а затем получить его следующим образом:

IResolutionRoot.Get<IRootScope>(new NamedScopeParameter(scopeName));

Таким образом, вам не нужно DefinesNamedScope(),

Другие вопросы по тегам