c# - Ninject 拦截代理类与非空构造函数通过 caSTLe 动态代理

标签 c# ninject aop castle-dynamicproxy ninject-interception

我目前的大部分实现都基于此处提供的信息:

Ninject Intercept any method with certain attribute?

我使用自定义规划策略类来查找具有给定属性(不是 ninject 拦截器属性)的所有方法,如果符合条件,这些方法将被代理。

一个用法示例是:

Kernel.Components.Add<IPlanningStrategy, CustomPlanningStrategy<LoggingAttribute, LoggerInterceptor>>();

然后这将查找任何具有 [Logging] 的方法属性,然后将使用日志记录拦截器。

但是,当动态代理尝试代理具有相关属性的方法时,我当前从动态代理中获取 InvalidProxyConstructorArgumentsException。现在我记得读过你需要虚方法,但我不记得看到你必须有一个无参数的构造函数。

所有绑定(bind)都是针对接口(interface)完成的,AOP 拦截器是通过属性和上面链接中提到的自定义代理规划类发生的。

那么有没有办法让动态代理(或linfu版本)来代理具有依赖构造函数的类? (所有依赖项都在内核中,因此它们并不是无法解析)。

最佳答案

查看代理生成代码: https://github.com/ninject/ninject.extensions.interception/blob/master/src/Ninject.Extensions.Interception.DynamicProxy/DynamicProxyProxyFactory.cs

    if (targetType.IsInterface)
        {
            reference.Instance = this.generator.CreateInterfaceProxyWithoutTarget(targetType, additionalInterfaces, InterfaceProxyOptions, wrapper);
        }
        else
        {
            object[] parameters = context.Parameters.OfType<ConstructorArgument>()
                .Select(parameter => parameter.GetValue(context, null))
                .ToArray();
            reference.Instance = this.generator.CreateClassProxy(targetType, additionalInterfaces, ProxyOptions, parameters, wrapper);
        }

可以看到 ninject 的动态代理扩展只将 ConstructorArgument 传递给 CaSTLe 动态代理生成器。

因此 - 在不更改 ninject 扩展或创建您自己的扩展的情况下 - 您需要将所有依赖项作为构造函数参数传递。您还可以尝试属性/方法注入(inject)是否有效(参见 https://github.com/ninject/ninject/wiki/Injection-Patterns )。

如果您控制代码,您可以将接口(interface)添加到代理类,然后使用“interface proxy with target”。这允许将代理实例化与目标(代理类)实例化分离 --> 目标可以注入(inject)依赖项 ctor,而无需对 ninject(-extensions)进行任何更改。

澄清: 具有以下应代理的类:

public interface IBar { }

public class Foo 
{
     public Foo(IBar bar)
     {
     }
}

以及以下绑定(bind):

Bind<Foo>().ToSelf().Intercept().With<SomeInterceptor>();
Bind<IBar>().To<Bar>();

然后从 ninject 容器中检索一个 Foo:

IResolutionRoot.Get<Foo>();

不会工作。

将所有构造函数参数放在 ninject 上下文中以使其工作

但是,我们可以更改 Foo 的检索以使其工作:

var bar = IResolutionRoot.Get<IBar>();
IResolutionRoot.Get<Foo>(new ConstructorArgument("bar", bar);

现在这是次优的,因为 ninject 不会自动执行依赖项解析。

为代理类添加接口(interface)以使其更好地工作

我们可以通过使用“带目标的接口(interface)代理”来解决这个问题。 首先,我们向代理类添加一个接口(interface):

public interface IFoo{ }

public class Foo : IFoo
{
     public Foo(IBar bar)
     {
     }
}

然后我们将绑定(bind)更改为:

Bind<IFoo>().To<Foo>().Intercept().With<SomeInterceptor>();

然后从 ninject 容器中检索一个 Foo:

IResolutionRoot.Get<Foo>();

有效。

另一个可能更简单(更难看?)的解决方案 根据@Daniel 这有效: 向代理类型添加两个构造函数:

  • 一个没有参数的protected 构造函数。这一个用于 DynamicProxy 创建代理。
  • 一个带有参数的public/internal 构造函数,由 ninject 用来实例化代理类型。

Ninject 将自动选择其可以解析的参数最多的构造函数。

关于c# - Ninject 拦截代理类与非空构造函数通过 caSTLe 动态代理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22348731/

相关文章:

c# - 使用 Ninject OWIN 中间件在 OWIN 启动中依赖注入(inject) UserStore

c# - Ninject - 静态类中的内核?

c# - 有什么方法可以在不使用属性装饰的情况下将 AOP 应用于 .NET 库?

java - 包内所有方法的@AspectJ 切入点

java - 如果我将@Async 方法放在一个切面上,它会异步执行吗?

c# - 演示受限执行区域重要性的代码

c# - 如何在 EF Core 5 中为自定义 SQL 配置导航属性

c# - 如何从 Salesforce 获取 consumer Key 和 consumer Secret

c# - 当 ViewModel 使用构造函数注入(inject)时,如何在设计时使用 MVVM light 提供虚拟数据?

c# - 如何使用 C# 匹配正则表达式中的 "