我怎么知道IRegistrationBuilder.EnableInterfaceInterceptors()是否已经被



我用Autofac.Extras.DynamicProxy来写几个IInterceptors。它们可以单独使用,也可以同时使用。我希望这些拦截器的消费者能够轻松地将它们附加到autofacc注册,因此我为每个拦截器编写了一个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));
}
}

当使用其中一个扩展方法时,扩展方法可以很好地工作。但是,如果消费者同时使用扩展方法,如:

builder.RegisterAssemblyTypes(GetType().Assembly)
.AsImplementedInterfaces()
.WithCorrelationRoots()
.WithTelemetryLogging()
.PreserveExistingDefaults();

我得到一个关于创建代理的代理的异常:

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?

我相信这是由于EnableInterfaceInterceptors()被调用了两次,一次在每个扩展方法。

我宁愿不从扩展方法中删除对EnableInterfaceInterceptors()的调用,而强迫消费者记住自己调用它。相反,我希望能够根据是否已经调用它来有条件地调用它。

如何检查IRegistrationBuilder对象以确定是否已经进行了此调用,和/或使用其条件注册机制之一?比如:

if (!builder.EIIHasBeenCalled)
{
builder.EnableInterfaceInterceptors();
}
return builder.InterceptedBy(...

builder.EnableInterfaceInterceptors.OnlyIf(b => !b.EIIHasBeenCalled).InterceptedBy(...

你不能事后检查拦截位。但是,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();
}
}

不幸的是,当您使用它时,它看起来有点乱,因为ContainerBuilder是具有属性的。你得把它传进去

builder.RegisterAssemblyTypes(GetType().Assembly)
.AsImplementedInterfaces()
.WithCorrelationRoots(builder)
.PreserveExistingDefaults();

容器构建和注册不是多线程的,所以ContainsKey调用不会遇到任何竞争条件。

关于PropertyKey方法有一个警告-这基本上是每个注册类型唯一的,但如果你有一堆相同类型的服务,这可能是一个挑战。目前还没有一个好的方法来唯一地标识注册。我代表你提出了一个问题。与此同时,这是如何做到这一点的一个想法。

受到Travis回应的启发,我在IRegistrationBuilder中找到了一本字典,我正在成功地使用它。现在我的代码看起来像这样:

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;
}

谢谢Travis给我的灵感!

最新更新