Ninject 拦截 - 移植到 Ninject 3.0 时的重大更改

标签 ninject aop interceptor ninject-extensions ninject-interception

我将描述我的环境:我有 Ninject + Ninject Interception Extension 工作以启用所有方法的拦截器的自动注册,并标有特殊属性。是常见的 AoP + 属性 + DI 容器场景。

我的问题是:
当移植到最新版本的 Ninject 和 Ninject Interception Extension - 3.0 时,当我的拦截器应该运行时,我开始遇到异常。在解析属性类型和注册拦截器时,我的 InterceptorRegistrationStrategy 工作正常。但是运行被拦截的方法会导致以下异常:

System.ArgumentException : Interface not found.
at System.RuntimeTypeHandle.VerifyInterfaceIsImplemented(RuntimeTypeHandle handle, RuntimeTypeHandle interfaceHandle)
at System.RuntimeType.GetInterfaceMap(Type ifaceType)
at Ninject.Extensions.Interception.Advice.Advice.MatchesMethod(IProxyRequest request)
at System.Linq.Enumerable.WhereListIterator`1.MoveNext()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList(IEnumerable`1 source)
at Ninject.Extensions.Interception.Registry.AdviceRegistry.GetInterceptorsForRequest(IProxyRequest request)
at Ninject.Extensions.Interception.Registry.AdviceRegistry.GetInterceptors(IProxyRequest request)
at Ninject.Extensions.Interception.Wrapper.StandardWrapper.CreateInvocation(IProxyRequest request)
at Ninject.Extensions.Interception.Wrapper.DynamicProxyWrapper.Intercept(IInvocation castleInvocation)
at Castle.DynamicProxy.AbstractInvocation.Proceed()
at Infrastructure.Tests.Persistance.Conversations.NinjectConversationInterceptorBehavior.ShouldCreateInterceptorOnImplicitConversation() in NinjectConversationInterceptorBehavior.cs: line 74 

我有点不得不求助于 Reflector 并使用 Ninject Interception Extension 源来解决这个问题,再加上没有足够的文档,这让我处于不利的境地。

移植到 Ninject 3.0 时有人遇到同样的异常吗?

这是我用来根据属性自动注册拦截器的代码:
public class NinjectConversationInterceptorRegistrationStrategy : InterceptorRegistrationStrategy
{
    public NinjectConversationInterceptorRegistrationStrategy(IAdviceFactory adviceFactory,
                                                              IAdviceRegistry adviceRegistry)
        : base(adviceFactory, adviceRegistry)
    {
    }

    public override void Execute(IPlan plan)
    {
        var pcAttribute = plan.Type.GetOneAttribute<PersistenceConversationalAttribute>();

        if (pcAttribute != null)
        {
            if (pcAttribute.MethodsIncludeMode == MethodsIncludeMode.Implicit)
            {
                foreach (var mi in GetCandidateMethods(plan.Type))
                {
                    RegisterMethodInterceptors(plan.Type, mi);
                    if (!plan.Has<ProxyDirective>())
                    {
                        plan.Add(new ProxyDirective());
                    }
                }
            }
            else
            {
                foreach (
                    var mi in
                        GetCandidateMethods(plan.Type).Where(
                            mi => mi.HasAttribute<PersistenceConversationAttribute>()))
                {
                    if (!mi.IsVirtual)
                    {
                        throw new InvalidOperationException(
                            string.Format("[PersistentCoversation] attribute used on non-virtual method {0}.{1}",
                                          mi.DeclaringType.Name,
                                          mi.Name));
                    }
                    RegisterMethodInterceptors(plan.Type, mi);
                    if (!plan.Has<ProxyDirective>())
                    {
                        plan.Add(new ProxyDirective());
                    }
                }
            }
        }
    }

    protected virtual void RegisterMethodInterceptors(Type type, MethodInfo method)
    {
        IAdvice advice = this.AdviceFactory.Create(method);
        advice.Callback = GetIntercepor;
        this.AdviceRegistry.Register(advice);
    }

    protected virtual IInterceptor GetIntercepor(IProxyRequest arg)
    {
        var interceptor = new NinjectConversationLazyInterceptor(arg.Kernel);
        return interceptor;
    }

    protected override bool ShouldIntercept(MethodInfo methodInfo)
    {
        if (IsPropertySetter(methodInfo))
        {
            return false;
        }
        var ret = base.ShouldIntercept(methodInfo);
        return ret;
    }

    private static bool IsPropertySetter(MethodBase methodInfo)
    {
        return methodInfo.IsSpecialName && methodInfo.Name.StartsWith("set_");
    }
}

最佳答案

拦截的行为发生了变化:当注入(inject)接口(interface)而不是类代理时,扩展将创建一个接口(interface)代理,因为这样的优点是方法不再需要是虚拟的。要么你必须把它放到接口(interface)中,从拦截中排除方法(拦截一个无论如何都不能调用的方法是没有用的)或者注入(inject)一个类而不是一个接口(interface)

关于Ninject 拦截 - 移植到 Ninject 3.0 时的重大更改,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10206827/

相关文章:

asp.net-mvc-3 - 如何使用 Ninject 将服务注入(inject)到 MVC 3 FilterAttributes 中?

aop - AspectJ:切入点中的参数

java - 使用 AspectJ 的日志 Controller

java - 获取拦截器中 View 发送的特定参数

java - 如何从拦截器访问注释变量

dependency-injection - ActionFilterAttribute ninject 注入(inject) - DbContext 已被释放

c# - 在 ASP.NET MVC 3 中注入(inject) IPrincipal - 我做错了什么?

java - Spring AOP - 在调用 setter 之前获取旧字段值

c# - 如何使用 C# 创建 gRPC 流拦截器?

c# - 我的webapi项目还依赖数据访问层吗?