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

Method-level attributed interception with 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..
   }
}

然后我这样注册Unity:

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

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

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

我正在 Simple Injector 中探索类似的方法来做到这一点。从我阅读和搜索的内容来看,似乎只有 interface/type 级别的拦截可用。但我喜欢用这种类型的属性控制拦截行为来装饰单个方法的选项。有什么建议吗?

[编辑:将 Autofac 移至其 own question 以保持此问题的重点]

Simple Injector 没有对动态拦截的开箱即用支持,因为这不符合其设计原则,如 here. Interception capabilities can be added however, for instance using Castle DynamicProxy as shown here 所述。也应该可以在 Simple Injector 之上使用 Unity 的拦截功能,但我从未尝试过。

但是,当使用 DynamicProxy 时,您必须将拦截器 class 与属性 class 分开。这实际上是一个更好的做法,因为这会保留您的属性 passive 并防止强制您的代码库依赖于拦截库。

使用 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
        }
    }
}

然而,Simple Injector 通过应用 SOLID 原则并使用装饰器来促进面向方面的编程。在我编写的应用程序中,我定义了通用抽象,例如 ICommandHandler<TCommand>IQueryHandler<TQuery, TResult>。这使得通过装饰器应用缓存变得微不足道。装饰器的优点在于它们更简洁(因为它们不依赖任何外部库)并且性能更高。