Autofac 是一个免费的 IoC 容器。我将 Autofac 与 Autofac.Extras.DynamicProxy2 一起使用nuget https://www.nuget.org/packages/Autofac.Extras.DynamicProxy2/, docs http://autofac.readthedocs.org/en/latest/advanced/interceptors.html.
假设您知道为什么以及何时(而不是)使用拦截器,并且您想要拦截某些功能:
public class FooService : IFooService
{
public void MoreFoo()
{
DoSomething();
}
public void LessFoo()
{
DoSomethingElse();
}
}
它需要“有线”。我喜欢属性,因为您不需要在 IoC 容器接线时显式指定拦截器。您只需指定一个要注意的属性:
[Intercept(typeof(Logger)]
public class FooService : IFooService { ... }
并接线:
var builder = new ContainerBuilder();
builder.RegisterType<FooService>()
.EnableClassInterceptors();
然后在另一个文件中创建 Logger 拦截器:
class Logger : IInterceptor
{
public void Intercept(IInvocation invocation) // implements the IInterceptor interface
{
_loggerService.Log("calling " + invocation.Method.Name);
invocation.Proceed();
_loggerService.Log("finished " + invocation.Method.Name);
}
}
正如您所看到的,您可以创建计时器、try-catch 块等等。数据库上下文和其他一次性资源是一个有趣的资源:
class Logger : IInterceptor
{
public void Intercept(IInvocation invocation) // implements the IInterceptor interface
{
using (var someThing = new SomeResource())
{
invocation.Proceed();
}
}
}
通常对于这样的资源,您需要在方法中使用 someThing。这是另一个问题的主题! (请参阅 invoking.SetArgumentValue 或 invoking.TargetType.GetProperties() 与封闭类进行通信。我对此不是 100% 满意,因此其他人的一些评论会有所帮助)
然后,以日志记录为例:
void ManageFoo()
{
// sorry for the messy code, what else can I do?!
_logger("more foo please");
_fooService.MoreFoo();
_logger("less foo please");
_fooService.LessFoo();
_logger("enough foo");
}
ManageFoo 方法的实际关注点在所有混乱的日志记录中消失了(添加安全性和其他问题,最终可能会陷入一团糟)。
现在你可以像这样重写它:
void ManageFoo()
{
_fooService.MoreFoo();
_fooService.LessFoo();
}