【问题标题】:Ninject Intercept any method with certain attribute?Ninject 拦截具有特定属性的任何方法?
【发布时间】:2021-12-11 04:31:19
【问题描述】:

我怎样才能让 Ninject.Extensions.Interception 基本上让我将特定的拦截器绑定到任何具有属性的方法...psudocode:

Kernel.Intercept(context => context.Binding.HasAttribute<TransactionAttribute>())
      .With<TransactionInterceptor>

类如下:

public SomeClass
{
    [TransactionAttribute]
    public void SomeTransactedMethod()
    { /*do stuff */ }
}

【问题讨论】:

    标签: ninject aop ninject-interception


    【解决方案1】:

    假设您正在使用 Ninject.Extensions.Interception 这应该可以解决问题

    public class TransactionInterceptor : IInterceptor
    {
        public void Intercept(IInvocation invocation)
        {
            // Do something...
        }
    }
    
    public class TransactionAttribute : InterceptAttribute
    {
        public override IInterceptor CreateInterceptor(IProxyRequest request)
        {
            return new TransactionInterceptor();
        }
    }
    
    public class SomeClass
    {
        [Transaction]
        public virtual void SomeTransactedMethod() { }
    }
    

    确保应该拦截的方法被标记为虚拟。

    SomeTransactedMethod()被调用时,它应该被拦截。

    var kernel = new StandardKernel();
    kernel.Bind<SomeClass>().ToSelf();
    
    var someClass = kernel.Get<SomeClass>();
    someClass.SomeTransactedMethod();
    

    更新

    您可以创建自定义规划策略。

    public class CustomPlanningStrategy<TAttribute, TInterceptor> :
        NinjectComponent, IPlanningStrategy
            where TAttribute : Attribute
            where TInterceptor : IInterceptor
    {
        private readonly IAdviceFactory adviceFactory;
        private readonly IAdviceRegistry adviceRegistry;
    
        public CustomPlanningStrategy(
            IAdviceFactory adviceFactory, IAdviceRegistry adviceRegistry)
            {
                this.adviceFactory = adviceFactory;
                this.adviceRegistry = adviceRegistry;
            }
    
            public void Execute(IPlan plan)
            {
                var methods = GetCandidateMethods(plan.Type);
                foreach (var method in methods)
                {
                    var attributes = method.GetCustomAttributes(
                        typeof(TAttribute), true) as TAttribute[];
                    if (attributes.Length == 0)
                    {
                        continue;
                    }
    
                    var advice = adviceFactory.Create(method);
    
                    advice.Callback = request => request.Kernel.Get<TInterceptor>();
                    adviceRegistry.Register(advice);
    
                    if (!plan.Has<ProxyDirective>())
                    {
                        plan.Add(new ProxyDirective());
                    }
                }
            }
        }
    
        private static IEnumerable<MethodInfo> GetCandidateMethods(Type type)
        {
            var methods = type.GetMethods(
                BindingFlags.Public | 
                BindingFlags.NonPublic | 
                BindingFlags.Instance
            );
    
            return methods.Where(ShouldIntercept);
        }
    
        private static bool ShouldIntercept(MethodInfo methodInfo)
        {
            return methodInfo.DeclaringType != typeof(object) &&
                   !methodInfo.IsPrivate &&
                   !methodInfo.IsFinal;
        }
    }
    

    现在应该可以了。

    var kernel = new StandardKernel();
    kernel.Components.Add<IPlanningStrategy, 
        CustomPlanningStrategy<TransactionAttribute, TransactionInterceptor>>();
    
    kernel.Bind<SomeClass>().ToSelf();
    
    var someClass = kernel.Get<SomeClass>();
    someClass.SomeTransactedMethod();
    

    【讨论】:

    • 不能让我的属性从 InterceptAttribute 继承,因为定义事务属性的域不知道 DI 问题......这就是为什么我需要通过 Kernel.Intercept 方法来做,这是在应用层中定义的。
    • 好的,我现在明白了……我已经对 IPlanningStrategy 做了一个粗略的实现,希望能解决问题。您可能想在 Github 上查阅 Ninject.Extensions.Inteception 的实际代码,以了解改进自定义规划策略的方法。
    • 嗯似乎比我所追求的要多一些工作......我确信不久前我看到了一个使用内核上的拦截扩展方法的简单的一个衬里的例子,会给它另一个在互联网上搜索,如果所有其他方法都失败,请尝试上述...谢谢。
    • 看来没有其他办法了,所以用你的方法。感谢您花时间写下来,会给你答案!
    • 您可以简单地调用 .Intercept().With&lt;SomeInterceptor&gt;() 而不是代码 AFAIK 上的这组代码。看看 Ninject 拦截扩展。
    【解决方案2】:

    这是我用于相同目的的代码

    //Code in Bind Module
    this.Bind(typeof(ServiceBase<,>))
        .ToSelf()
        .InRequestScope()
        .Intercept()
        .With<TransactionInterceptor>();
    

    public class TransactionInterceptor : IInterceptor
    {
        #region Constants and Fields
    
        public ISession session;
        private ISessionFactory sessionFactory;
    
        #endregion
    
        #region Constructors and Destructors
    
        public TransactionInterceptor(ISession session, ISessionFactory sessionFactory)
        {
            this.sessionFactory = sessionFactory;
            this.session = session;
        }
    
    
        #endregion
    
        public void Intercept(IInvocation invocation)
        {
            try
            {
                if (!session.IsConnected)
                    session = sessionFactory.OpenSession();
    
                session.BeginTransaction();
                invocation.Proceed();
                if (this.session == null)
                {
                    return;
                }
    
                if (!this.session.Transaction.IsActive)
                {
                    return;
                }
                else
                {
                    this.session.Transaction.Commit();
                }
            }
            catch (Exception)
            {
                if (this.session == null)
                {
                    return;
                }
    
                if (!this.session.Transaction.IsActive)
                {
                    return;
                }
    
                this.session.Transaction.Rollback();
    
                throw;
            }
        }
    }
    

    TransactionAttribute 的代码

    public class TransactionAttribute : InterceptAttribute
    {
        #region Public Methods
    
        public override IInterceptor CreateInterceptor(IProxyRequest request)
        {
            return request.Context.Kernel.Get<TransactionInterceptor>() ;
        }
    
        #endregion
    }
    

    【讨论】:

      猜你喜欢
      • 2013-08-21
      • 2012-11-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多