【问题标题】:Using Ninject, how can I use property injection, Lazy<>, and interception without encountering errors in castle.core?使用 Ninject,如何使用属性注入、Lazy<> 和拦截,而不会在 Castle.core 中遇到错误?
【发布时间】:2026-01-22 21:40:01
【问题描述】:

我为使用 ASP.NET Webforms 的旧 SharePoint On-Prem 项目创建了一个简单的程序作为 PoC。在它的页面中,我必须使用属性注入,而对于其他一切,我可以使用构造函数注入。我也在使用:

  • 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:无法从程序集“DynamicProxyGenAssembly2,Version=0.0.0.0,Culture=neutral,PublicKeyToken=a621a9e7e5c32e69”加载类型“Castle.Proxies.Func`2Proxy”,因为父类型是密封的。

如果我删除“Lazy”,它将重新引入循环依赖。如果我删除拦截,它不会有任何错误,但我需要拦截器。而且,我必须在页面上使用属性注入,因为页面的构造函数是由 webforms 管理的,没有像 MVC 领域那样有用的钩子。注意:使用网络表单是因为使用了 SharePoint 2013。

任何想法如何在不遇到上述错误的情况下保持拦截和延迟声明?

【问题讨论】:

  • 对不起,我认为我之前的回答是错误的。解决方案仍然可能是从代理中排除某些类型,但不会出现异常,因为Lazysealed。此外,Func&lt;..&gt; 也不是,似乎有代码可以成功使用Func2Proxy`。
  • 能否提供一个完整的 Stacktrace 异常?
  • 你也可以通过使用 Ninject.Extensions.Factory 将Lazy&lt;&gt; 替换为Func&lt;&gt; 来消除循环依赖的问题
  • @BatteryBackupUnit - 你的回答帮助我想出了一个解决方案。
  • @jbl - 感谢您的信息。我仍然会收到 Func 的错误,但很高兴知道。

标签: c# webforms ninject ninject-extensions ninject-interception


【解决方案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 的拦截扩展发生了什么。

欢迎任何更好的解决方案!

【讨论】:

    最近更新 更多