I'm using Autofac.Extras.DynamicProxy to write a couple of IInterceptors. 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:
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.
I'd rather not remove the calls to EnableInterfaceInterceptors() from the extension methods and force the consumers to remember to call it themselves. 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? 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,
ContainerBuilderhas aPropertiesdictionary that you could use.Unfortunately, it looks a little messy when you use it because the
ContainerBuilderis what has the properties. You'd have to pass that in.Container building and registration isn't multi-threaded so you won't hit any race conditions with that
ContainsKeycall.There is a caveat on the
PropertyKeymethod - 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. 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.