如果不查看您的代码,很难判断这是否是一个适用的解决方案,但如果您有一个对DI 友好的应用程序架构,您可以实现一个拦截器并让您最喜欢的 IoC 容器在运行时为您发出适当的类型。
深奥?一点。考虑这样的接口:
public interface ISomeService
{
IEnumerable<SomeEntity> GetSomeEntities();
// ...
}
这个接口可能是这样实现的:
public class SomeService : ISomeService
{
private readonly DbContext _context // this is a dependency!
private readonly IQueryTweaker _tweaker; // this is a dependency!
public SomeService(DbContext context, IQueryTweaker tweaker) // this is constructor injection!
{
_context = context;
_tweaker = tweaker;
}
public IEnumerable<SomeEntity> GetSomeEntities()
{
return _tweaker.TweakTheQuery(_context.SomeEntities).ToList();
}
}
每次你实现接口的一个方法时,总会有一个对包装的ISomeService
调用,这不仅会让人感到无聊,而且感觉就像缺少一个功能——就像包装每个调用一样在/块内,或者如果您熟悉 WPF 中的 MVVM,请为 ViewModel 中的每个属性设置器引发这个烦人的事件。_tweaker.TweakTheQuery()
IQueryable
try
catch
PropertyChanged
使用 DI 拦截,你将这个要求从你的“正常”代码中分解到一个“拦截器”中:你基本上告诉 IoC 容器,而不是ISomeService
直接绑定到SomeService
实现,你将用一个拦截器来装饰它,并且发出另一种类型,也许SomeInterceptedService
(名称无关紧要,实际类型仅在运行时存在),它将所需的行为“注入”到所需的方法中。简单的?不完全是。
如果您在设计代码时没有考虑 DI(您的依赖项是否“注入”到类的构造函数中?),这可能意味着重大重构。
第一步会破坏您的代码:从所有实现中删除IQueryTweaker
依赖项和所有TweakTheQuery
调用ISomeService
,使它们看起来像这样 - 注意virtual
要拦截的方法的性质:
public class SomeService : ISomeService
{
private readonly DbContext _context
public SomeService(DbContext context)
{
_context = context;
}
public virtual IEnumerable<SomeEntity> GetSomeEntities()
{
return _context.SomeEntities.ToList();
}
}
下一步是配置 IoC 容器,以便它知道在SomeService
类型的构造函数需要时注入实现ISomeService
:
_kernel.Bind<ISomeService>().To<SomeService>();
此时您已准备好配置拦截 -如果使用 Ninject 这可能会有所帮助。
但是在跳进兔子洞之前,你应该阅读这篇文章,它展示了装饰器和拦截器是如何相关的。
关键是,您不会拦截LINQ to SQL 或 .NET 框架本身内部的任何内容 -您正在拦截自己的方法调用,用自己的代码包装它们,并得到任何体面的帮助IoC 容器,您将拦截对调用Linq to SQL 的方法的调用,而不是直接调用 Linq to SQL 本身。本质上,IQueryTweaker
依赖项变成了拦截器类的依赖项,您只需编写一次它的用法。
关于 DI 拦截的一个有趣的事情是,拦截器可以组合起来,所以你可以在 aExecutionTimerServiceInterceptor
之上AuditServiceInterceptor
,在 a 之上CircuitBreakerServiceInterceptor
......,最好的部分是你可以配置你的 IoC 容器,这样你就可以完全忘记它存在,并且当您向应用程序添加更多服务类时,您需要做的就是遵循您定义的命名约定,瞧,您刚刚编写了一个服务,它不仅可以完成所有与数据严格相关的任务'刚刚编写了代码,但如果数据库服务器关闭,该服务将自行禁用 3 分钟,并在备份之前保持禁用状态;该服务还记录所有插入、更新和删除,并将其执行时间存储在数据库中以进行性能分析。自动魔法这个词似乎合适。
这种技术——拦截——可以用来解决横切关注点;解决这些问题的另一种方法是通过 AOP,尽管一些文章(以及 Mark Seeman在 .NET 中的出色依赖注入)清楚地展示了 AOP 框架如何不是 DI 拦截的理想解决方案。