使用Simple Injector进行方法级别的属性拦截

Cal*_*vin 5 c# dependency-injection ioc-container simple-injector

使用Unity,我可以快速添加基于属性的拦截

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..
   }
}
Run Code Online (Sandbox Code Playgroud)

然后我这样注册Unity:

container.RegisterType<IPlanRepository, PlanRepository>(
    new ContainerControlledLifetimeManager(),
    new Interceptor<VirtualMethodInterceptor>(),
    new InterceptionBehavior<PolicyInjectionBehavior>());
Run Code Online (Sandbox Code Playgroud)

在我的存储库代码中,我可以选择性地装饰要缓存的某些方法(具有可以为每个方法单独定制的属性值):

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

我在Simple Injector中探索类似的方法.从我读取和搜索的内容看起来只有接口/类型级别拦截可用.但我希望能够选择使用这种属性控制的拦截行为来装饰各个方法.有什么建议吗?

[编辑:将Autofac移至自己的问题以保持此问题的重点]

Ste*_*ven 5

简单的注射器缺乏外的现成功能做动态拦截,因为这不符合它的设计原则,解释在这里.拦截能力可以用但城堡DynamicProxy如图所示添加,例如在这里.也应该可以在Simple Injector之上使用Unity的拦截功能,但我从未尝试过.

但是,在使用DynamicProxy时,必须将拦截器类与属性类分开.这实际上是一种更好的做法,因为这会使您的属性保持被动,并防止强制您的代码库依赖于拦截库.

使用DynamicProxy实现此功能时,它可能如下所示:

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

        if (attribute == null) {
            // Pass through without applying caching
            invocation.Proceed();
        } else {
           // apply caching here
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然而,Simple Injector通过应用SOLID原则和使用装饰器来促进面向方面编程.在我编写的应用程序中,我定义了诸如ICommandHandler<TCommand>和的通用抽象IQueryHandler<TQuery, TResult>,这使得通过装饰器应用缓存变得微不足道.装饰器的好处在于它们更清洁(因为它们根本不依赖于任何框架)并且性能更高.