您可以动态添加拦截器,但需要做一些工作。要走的路是创建一个自定义的Autofac.Module 附加到所有组件注册。我将通过示例向您展示。
你不能真正在全局范围内执行EnableInterfaceInterceptors。我将在示例结束时进行说明。
首先,示例设置:我们有一个简单的接口、一个简单的实现和一个用于处理日志调用的拦截器。 (我在窃取拦截器代码from the Autofac wiki):
public interface IInterface
{
void DoWork();
}
public class Implementation : IInterface
{
public void DoWork()
{
Console.WriteLine("Implementation doing work.");
}
}
public class CallLogger : IInterceptor
{
TextWriter _output;
public CallLogger(TextWriter output)
{
_output = output;
}
public void Intercept(IInvocation invocation)
{
_output.WriteLine("Calling method {0} with parameters {1}... ",
invocation.Method.Name,
string.Join(", ", invocation.Arguments.Select(a => (a ?? "").ToString()).ToArray()));
invocation.Proceed();
_output.WriteLine("Done: result was {0}.", invocation.ReturnValue);
}
}
我们希望通过调用记录器拦截所有内容(启用了拦截器)。我们通过创建自定义 Autofac.Module 来实现,该 Autofac.Module 将拦截器本身注册到 Autofac 并附加到组件注册快速添加拦截器元数据。
警告:这里有一点黑客攻击,它可以工作,但有点“将数据”“插入”到某种已知的位置。它有效,我不知道它为什么会改变,但请注意,因为它有点像是在处理“私人”的东西,这可能会在未来的版本中中断。请注意。
好的,免责声明完成。这是模块:
public class InterceptorModule : Autofac.Module
{
// This is a private constant from the Autofac.Extras.DynamicProxy2 assembly
// that is needed to "poke" interceptors into registrations.
const string InterceptorsPropertyName = "Autofac.Extras.DynamicProxy2.RegistrationExtensions.InterceptorsPropertyName";
protected override void Load(ContainerBuilder builder)
{
// Register global interceptors here.
builder.Register(c => new CallLogger(Console.Out));
}
protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration)
{
// Here is where you define your "global interceptor list"
var interceptorServices = new Service[] { new TypedService(typeof(CallLogger)) };
// Append the global interceptors to any existing list, or create a new interceptor
// list if none are specified. Note this info will only be used by registrations
// that are set to have interceptors enabled. It'll be ignored by others.
object existing;
if (registration.Metadata.TryGetValue(InterceptorsPropertyName, out existing))
{
registration.Metadata[InterceptorsPropertyName] =
((IEnumerable<Service>)existing).Concat(interceptorServices).Distinct();
}
else
{
registration.Metadata.Add(InterceptorsPropertyName, interceptorServices);
}
}
}
要使其工作,您需要将模块与其他依赖项一起注册。对于这个例子,它看起来像:
var builder = new ContainerBuilder();
// Notice this registration doesn't include
// the interceptor - that gets added by the
// module.
builder.RegisterType<Implementation>()
.As<IInterface>()
.EnableInterfaceInterceptors();
// Here's the magic module:
builder.RegisterModule<InterceptorModule>();
var container = builder.Build();
如果您运行这些注册并解决...
var impl = container.Resolve<IInterface>();
impl.DoWork();
您可以看到拦截器的工作原理,就像您将看到控制台输出一样:
Calling method DoWork with parameters ...
Implementation doing work.
Done: result was .
(这有点奇怪,因为我的示例中有一个无参数/void 方法,但拦截器正在工作!)
至于EnableInterfaceInterceptors 调用... 执行EnableInterfaceInterceptors 或EnableClassInterceptors 实际上在后端做了很多疯狂的DynamicProxy2 工作。它向组件上的激活事件添加了一些重要的事件处理程序,将对象包装在动态代理中。这些事件处理程序目前没有公开用于单独使用,我不确定要像我们在此处使用实际拦截器所做的那样尝试“事后”附加所有这些东西需要做多少工作。
欢迎您亲自尝试 - the source is on GitHub。但是,基本上,虽然“添加全局拦截器”的工作有效,但在模块中执行全局 EnableInterfaceInterceptors 却远非人迹罕至。你肯定会独自一人。