Используя Ninject, как я могу использовать инъекцию свойств, Lazy<> и перехват, не встречая ошибок в castle.core?

Я создал простую программу в качестве PoC для старого проекта SharePoint On-Prem, использующего веб-формы ASP.NET. На его страницах я должен использовать инъекцию свойств, а для всего остального я могу использовать инжектор конструктора. Я также использую:

  • Ninject.Extensions.Factory
  • Ninject.Extensions.Interception
  • Ninject.Extensions.Interception.DynamicProxy

Все работало относительно хорошо, пока я не добавил перехватчики и не использовал Lazy<> для решения некоторых циклических зависимостей. Чтобы упростить это в примере, я написал следующий пример как консольное приложение:

public class Program
{
    static void Main(string[] args)
    {
        IKernel kernel = new StandardKernel(
            new NinjectSettings() { LoadExtensions = false },
            new DynamicProxyModule(),
            new FuncModule());

        kernel.Bind<ISomeClass>().To<SomeClass>();
        kernel.Bind<IOtherClass>().To<OtherClass>();
        kernel.Bind<IAnotherClass>().To<AnotherClass>();

        kernel.Intercept(p => true).With(new ClassInterceptor()); // Removing this works, but I need the interceptors.

        ISomeClass someClass = kernel.TryGet<ISomeClass>();

        someClass.Foo();
    }

    public interface ISomeClass
    {
        void Foo();
    }

    public class SomeClass : ISomeClass
    {
        [Inject]
        public IOtherClass OtherClass { get; set; }

        public SomeClass() { }

        public void Foo()
        {
            Console.WriteLine("Foo");

            this.OtherClass.Bar();
        }
    }

    public interface IOtherClass
    {
        void Bar();
    }

    public class OtherClass : IOtherClass
    {
        private readonly Lazy<IAnotherClass> _anotherClass;

        public IAnotherClass AnotherClass { get { return this._anotherClass.Value; } }

        public OtherClass(Lazy<IAnotherClass> anotherClass)
        {
            this._anotherClass = anotherClass;
        }

        public void Bar()
        {
            Console.WriteLine("Bar");
        }
    }

    public interface IAnotherClass
    {
        void FooBar();
    }

    public class AnotherClass : IAnotherClass
    {
        private readonly Lazy<IOtherClass> _otherClass;

        public IOtherClass OtherClass { get { return this._otherClass.Value; } }

        public AnotherClass(Lazy<IOtherClass> otherClass)
        {
            this._otherClass = otherClass;
        }

        public void FooBar()
        {
            Console.WriteLine("FooBar");

            this.OtherClass.Bar();
        }
    }

    public class ClassInterceptor: SimpleInterceptor
    {
        public ClassInterceptor() { }

        protected override void BeforeInvoke(IInvocation invocation)
        {
            base.BeforeInvoke(invocation);

            Console.WriteLine("I'm doing stuff before.");
        }

        protected override void AfterInvoke(IInvocation invocation)
        {
            base.BeforeInvoke(invocation);

            Console.WriteLine("I'm doing stuff after.");
        }
    }
}

В результате я получаю следующую ошибку:

Необработанное исключение: System.TypeLoadException: не удалось загрузить тип 'Castle.Proxies.Func`2Proxy' из сборки 'DynamicProxyGenAssembly2, версия =0.0.0.0, Culture= нейтральный, PublicKeyToken=a621a9e7e5c32e69', так как родительский тип закрыт.

Если я удалю "Ленивый<>", он снова введет циклические зависимости. Если я уберу перехват, у него не будет никаких ошибок, но мне нужны перехватчики. И я должен использовать инъекцию свойств на страницах, потому что конструкторы страниц управляются веб-формами без каких-либо полезных хуков, как в MVC land. ПРИМЕЧАНИЕ. Веб-формы используются потому, что используется SharePoint 2013.

Любые идеи, как сохранить и перехват, и объявления Lazy<>, не обнаружив ошибки выше?

1 ответ

Я смог решить эту проблему, не добавляя перехватчики ко всему ядру, так как были некоторые типы, для которых не могли быть созданы прокси. Учитывая, что списки исключений были, вероятно, больше, чем я встречал, я выбрал следующий лучший вариант, который заключался в применении глобальных перехватчиков индивидуально к каждой привязке:

    static void Main(string[] args)
    {
        IKernel kernel = new StandardKernel(
            new NinjectSettings() { LoadExtensions = false },
            new DynamicProxyModule(),
            new FuncModule());

        AddInterceptors(kernel.Bind<ISomeClass>().To<SomeClass>());
        AddInterceptors(kernel.Bind<IOtherClass>().To<OtherClass>());
        AddInterceptors(kernel.Bind<IAnotherClass>().To<AnotherClass>());

        //kernel.Intercept(p => true).With(new ClassInterceptor());

        ISomeClass someClass = kernel.TryGet<ISomeClass>();

        someClass.Foo();
    }

    private static void AddInterceptors<T>(IBindingWhenInNamedWithOrOnSyntax<T> binding)
    {
        binding.Intercept(p => true).With(new ClassInterceptor());
        /* ... other interceptors ... */
    }

Спасибо, что сообщили мне, что происходит с расширением перехвата, пытающимся создать прокси для Lazy и T, @BatteryBackupUnit.

Любые лучшие решения приветствуются!

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