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移至自己的问题以保持此问题的重点]
简单的注射器缺乏外的现成功能做动态拦截,因为这不符合它的设计原则,解释在这里.拦截能力可以用但城堡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>,这使得通过装饰器应用缓存变得微不足道.装饰器的好处在于它们更清洁(因为它们根本不依赖于任何框架)并且性能更高.