[英]How can I tell if IRegistrationBuilder.EnableInterfaceInterceptors() has already been called?
I'm using Autofac.Extras.DynamicProxy
to write a couple of IInterceptor
s.我正在使用
Autofac.Extras.DynamicProxy
编写几个IInterceptor
。 They can be used individually, or both together.它们可以单独使用,也可以同时使用。 I want consumers of these interceptors to be able to attach them to Autofac registrations easily, so I wrote an
IRegistrationBuilder
extension method for each of them:我希望这些拦截器的使用者能够轻松地将它们附加到 Autofac 注册,因此我为它们中的每一个编写了一个
IRegistrationBuilder
扩展方法:
public static class RegistrationBuilderExtensions
{
public static IRegistrationBuilder<T, TActivatorData, TRegistrationStyle> WithTelemetryLogging<T, TActivatorData, TRegistrationStyle>(this IRegistrationBuilder<T, TActivatorData, TRegistrationStyle> builder)
{
return builder.EnableInterfaceInterceptors().InterceptedBy(typeof(TelemetryLoggingInterceptor));
}
public static IRegistrationBuilder<T, TActivatorData, TRegistrationStyle> WithCorrelationRoots<T, TActivatorData, TRegistrationStyle>(this IRegistrationBuilder<T, TActivatorData, TRegistrationStyle> builder)
{
return builder.EnableInterfaceInterceptors().InterceptedBy(typeof(NewCorrelationInterceptor));
}
}
The extension methods work well when one or the other is used.当使用一种或另一种时,扩展方法效果很好。 However, if a consumer uses both extension methods, as in:
但是,如果消费者使用两种扩展方法,如:
builder.RegisterAssemblyTypes(GetType().Assembly)
.AsImplementedInterfaces()
.WithCorrelationRoots()
.WithTelemetryLogging()
.PreserveExistingDefaults();
I get an exception about creating a proxy of a proxy:我得到一个关于创建代理的代理的异常:
Castle.DynamicProxy.ProxyGenerationException: This is a DynamicProxy2 error: Target type for the proxy implements Castle.DynamicProxy.IProxyTargetAccessor which is a DynamicProxy infrastructure interface and you should never implement it yourself. Are you trying to proxy an existing proxy?
I believe it's due to EnableInterfaceInterceptors()
being called twice, once in each extension method.我相信这是由于
EnableInterfaceInterceptors()
被调用了两次,一次在每个扩展方法中。
I'd rather not remove the calls to EnableInterfaceInterceptors()
from the extension methods and force the consumers to remember to call it themselves.我宁愿不从扩展方法中删除对
EnableInterfaceInterceptors()
的调用并强制消费者记住自己调用它。 Instead, I'd like to be able to conditionally call it based on whether or not it had already been called.相反,我希望能够根据它是否已经被调用来有条件地调用它。
How I can inspect the IRegistrationBuilder
object to determine if this call has already been made, and/or use one of its conditional registration mechanisms?我如何检查
IRegistrationBuilder
object 以确定是否已进行此调用,和/或使用其条件注册机制之一? Something like:就像是:
if (!builder.EIIHasBeenCalled)
{
builder.EnableInterfaceInterceptors();
}
return builder.InterceptedBy(...
or或者
builder.EnableInterfaceInterceptors.OnlyIf(b => !b.EIIHasBeenCalled).InterceptedBy(...
You can't inspect the interception bits post-facto.您无法事后检查拦截位。 However,
ContainerBuilder
has a Properties
dictionary that you could use.但是,
ContainerBuilder
有一个您可以使用的Properties
字典。
public static class RegistrationBuilderExtensions
{
public static IRegistrationBuilder<T, TActivatorData, TRegistrationStyle>
WithTelemetryLogging<T, TActivatorData, TRegistrationStyle>(
this IRegistrationBuilder<T, TActivatorData, TRegistrationStyle> builder, ContainerBuilder cb)
{
var key = PropertyKey(builder);
if(!cb.Properties.ContainsKey(key))
{
cb.Properties[key] = true;
return builder
.EnableInterfaceInterceptors()
.InterceptedBy(typeof(TelemetryLoggingInterceptor));
}
return builder;
}
public static IRegistrationBuilder<T, TActivatorData, TRegistrationStyle>
WithCorrelationRoots<T, TActivatorData, TRegistrationStyle>(
this IRegistrationBuilder<T, TActivatorData, TRegistrationStyle> builder, ContainerBuilder cb)
{
var key = PropertyKey(builder);
if(!cb.Properties.ContainsKey(key))
{
cb.Properties[key] = true;
return builder
.EnableInterfaceInterceptors()
.InterceptedBy(typeof(NewCorrelationInterceptor));
}
return builder;
}
private static string PropertyKey<T, TActivatorData, TRegistrationStyle>(IRegistrationBuilder<T, TActivatorData, TRegistrationStyle> registration)
{
// Uniquely identify the registration however you want.
return registration.GetType().ToString();
}
}
Unfortunately, it looks a little messy when you use it because the ContainerBuilder
is what has the properties.不幸的是,当您使用它时它看起来有点乱,因为
ContainerBuilder
是具有属性的东西。 You'd have to pass that in.你必须把它传进去。
builder.RegisterAssemblyTypes(GetType().Assembly)
.AsImplementedInterfaces()
.WithCorrelationRoots(builder)
.PreserveExistingDefaults();
Container building and registration isn't multi-threaded so you won't hit any race conditions with that ContainsKey
call.容器构建和注册不是多线程的,因此您不会通过
ContainsKey
调用遇到任何竞争条件。
There is a caveat on the PropertyKey
method - this will basically be unique per registration type but if you have a bunch of services that are identical types, that could be a challenge. PropertyKey
方法有一个警告 - 这基本上是每个注册类型唯一的,但如果你有一堆相同类型的服务,那可能是一个挑战。 There is not a good way right now to uniquely identify a registration.目前没有很好的方法来唯一标识一个注册。 I've filed an issue about this on your behalf.
我已代表您提交了关于此的问题。 In the meantime, this is one idea on how to do it.
与此同时,这是关于如何做到这一点的一个想法。
Inspired by Travis' response, I found a dictionary within IRegistrationBuilder
that I'm using with success.受特拉维斯回应的启发,我在
IRegistrationBuilder
中找到了一本我正在成功使用的字典。 I now have code that looks like this:我现在的代码看起来像这样:
const string MF_ENABLE_INTERFACE_INTERCEPTORS = "MFEnableInterfaceInterceptors";
public static IRegistrationBuilder<T, TActivatorData, TRegistrationStyle> WithTelemetryLogging<T, TActivatorData, TRegistrationStyle>(this IRegistrationBuilder<T, TActivatorData, TRegistrationStyle> builder)
{
if (!_AreInterfaceInterceptorsEnabled(builder))
{
builder.EnableInterfaceInterceptors();
_TrackEnableInterfaceInterceptors(builder);
}
return builder.InterceptedBy(typeof(TelemetryLoggingInterceptor));
}
public static IRegistrationBuilder<T, TActivatorData, TRegistrationStyle> WithCorrelationRoots<T, TActivatorData, TRegistrationStyle>(this IRegistrationBuilder<T, TActivatorData, TRegistrationStyle> builder)
{
if (!_AreInterfaceInterceptorsEnabled(builder))
{
builder.EnableInterfaceInterceptors();
_TrackEnableInterfaceInterceptors(builder);
}
return builder.InterceptedBy(typeof(CorrelatedInterceptor));
}
private static bool _AreInterfaceInterceptorsEnabled<T, TActivatorData, TRegistrationStyle>(IRegistrationBuilder<T, TActivatorData, TRegistrationStyle> builder)
{
if (builder.RegistrationData.Metadata.TryGetValue(MF_ENABLE_INTERFACE_INTERCEPTORS, out var metadata))
{
return (bool?)metadata ?? false;
}
return false;
}
private static void _TrackEnableInterfaceInterceptors<T, TActivatorData, TRegistrationStyle>(IRegistrationBuilder<T, TActivatorData, TRegistrationStyle> builder)
{
builder.RegistrationData.Metadata[MF_ENABLE_INTERFACE_INTERCEPTORS] = true;
}
Thanks, Travis, for the inspiration!谢谢特拉维斯的灵感!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.