方法级拦截归功于用简单的喷油器 [英] Method-level attributed interception with Simple Injector

查看:189
本文介绍了方法级拦截归功于用简单的喷油器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

通过团结,我能够快速添加属性基于拦截这样的

 公共密封类MyCacheAttribute:HandlerAttribute, ICallHandler 
{
公众覆盖ICallHandler CreateHandler(IUnityContainer容器)
{
返回这一点;
}

公共IMethodReturn调用(IMethodInvocation输入,GetNextHandlerDelegate GETNEXT)
{
//抓斗从缓存中,如果我有它,否则调用预期的方法调用..
}
}

然后我注册使用Unity这样的:

  container.RegisterType< IPlanRepository,PlanRepository>(
新ContainerControlledLifetimeManager(),
新型拦截< VirtualMethodInterceptor>() ,
新InterceptionBehavior&所述; PolicyInjectionBehavior>());

在我的资源库的代码,我可以有选择地布置一定的方法进行高速缓存(带属性值,可以单独定制为每个方法):

  [MyCache(分钟= 5,CacheType = CacheType.Memory,令= 100)] 
酒店的公共虚拟PlanInfo GetPlan(INT ID)
{
//调用数据存储获得此计划;
}



我在探索类似的方式在简单的喷油器要做到这一点。从我读搜查貌似只有接口/类型级别的拦截可用。但我很想装饰单个方法与此类型的属性控制的拦截行为的选项。任何建议




解决方案

简单喷油器缺乏外的现成功能做拦截,因为这不符合它的设计原则,解释的此处。拦截能力但是可以加入,比如使用城堡DynamicProxy这里 >。它也应该可以在简单的喷油器的顶部使用Unity的拦截能力,但我从来没有尝试过这一点。



然而,当使用DynamicProxy,你将不得不分开你的拦截器类从属性类。这实际上是一个更好的做法,因为这让你的属性被动 ,并防止强迫你的代码库采取的拦截库的依赖性



在与DynamicProxy实现这一点,它可能是这个样子:



<预类=郎-CS prettyprint-覆盖> 公共类MyCacheInterceptor:IInterceptor
{
公共无效拦截(IInvocation调用){
VaR方法= invocation.GetImplementationMethod();
var属性= method.GetCustomAttribute< MyCacheAttribute>();

如果(属性== NULL){
//调用装修实例。
invocation.Proceed();
}其他{
//缓存这里
}
}
}

公共静态类InvocationExtensions
{
酒店的公共静态的MethodInfo GetImplementationMethod(此IInvocation调用){
//注意:有点幼稚实现
VAR方法= invocation.GetConcreteMethod();
返回invocation.InvocationTarget.GetType()实现getMethod(method.Name)。
}
}



简单的注射器然而,促进应用面向方面编程SOLID原则和使用装饰代替。在我写的,我定义通用的抽象,例如 IRepository<的应用; TEntity> IQueryHandler< TQuery的,TResult> 这使通过装饰琐碎应用缓存。什么是关于装饰漂亮的是,他们更清洁(因为它们不依赖于任何所有框架)和更高性能的。


With Unity, I'm able to quickly add an attribute based interception like this

public sealed class MyCacheAttribute : HandlerAttribute, ICallHandler
{
   public override ICallHandler CreateHandler(IUnityContainer container)
   {
        return this;
   }

   public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
   {
      // grab from cache if I have it, otherwise call the intended method call..
   }
}

Then I register with Unity this way:

container.RegisterType<IPlanRepository, PlanRepository>(
    new ContainerControlledLifetimeManager(),
    new Interceptor<VirtualMethodInterceptor>(),
    new InterceptionBehavior<PolicyInjectionBehavior>());

In my repository code, I can selectively decorate certain methods to be cached (with attribute values that can be customized individually for each method) :

    [MyCache( Minutes = 5, CacheType = CacheType.Memory, Order = 100)]
    public virtual PlanInfo GetPlan(int id)
    {
        // call data store to get this plan;
    }

I'm exploring similar ways to do this in Simple Injector. From what I read and searched looks like only interface/type level interception is available. But I would love the option of decorating individual methods with this type of attribute controlled interception behavior. Any advise?

[Edit: moved Autofac to its own question to keep this question focused]

解决方案

Simple Injector lacks out-of-the-box features for doing interception, because this doesn't fit its design principles, as explained here. Interception capabilities can be added however, for instance using Castle DynamicProxy as shown here. It should also be possible to use Unity's interception capabilities on top of Simple Injector, but I never tried this.

When using DynamicProxy however, you will have to separate your interceptor class from the attribute class. This is actually a much better practice, because this keeps your attributes passive and prevents forcing your code base from taking a dependency on the interception library.

When implementing this with DynamicProxy, it might look something like this:

public class MyCacheInterceptor : IInterceptor 
{   
    public void Intercept(IInvocation invocation) {
        var method = invocation.GetImplementationMethod();
        var attribute = method.GetCustomAttribute<MyCacheAttribute>();

        if (attribute == null) {
            // Calls the decorated instance.
            invocation.Proceed();
        } else {
           // caching here
        }
    }
}

public static class InvocationExtensions
{
    public static MethodInfo GetImplementationMethod(this IInvocation invocation) {
        // NOTE: bit naive implementation
        var method = invocation.GetConcreteMethod();
        return invocation.InvocationTarget.GetType().GetMethod(method.Name);
    }
}

Simple Injector however, promotes Aspect-Oriented Programming by applying SOLID principles and using decorators instead. In the applications I write I define generic abstractions such as IRepository<TEntity> and IQueryHandler<TQuery, TResult> and this makes applying caching through decorators trivial. What's nice about decorators is that they are much cleaner (since they don't depend upon any framework at all) and much more performant.

这篇关于方法级拦截归功于用简单的喷油器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆