Turn on / off Interception [InterceptionBehavior]

Jun 27, 2014 at 10:09 PM
Hi , We are trying to implement logging using interception . We need to turn on/off the logging on the fly ...We don't want to create proxy when it is turned off.

What is the best way to remove the interception when we don't want to use it . Below is my container registration code

container.AddNewExtension<Interception>();
container.RegisterType<IInterceptTest, InterceptTest>(
new Interceptor<InterfaceInterceptor>(),
new InterceptionBehavior<LoggingInterceptionBehavior>()
);
Jun 30, 2014 at 2:41 PM
Once interception is enabled for a type then the build plan (implementing interception) will be cached so there is no straight forward way (e.g. set a boolean value somwhere) to disable interception. The easiest way would be to create a new container and re-register with the interception enabled/disabled. You would probably have to perform some global lock (either to replace the container or a DependencyResolver). All registrations could be done outside of the lock so the actual synchronized code would probably just be a set which would not have a huge performance impact.

Perhaps something like this could be useful:
container.RegisterType<IInterceptTest, IInterceptTest>(
    ApplyInterception(
        () => new InterceptionBehavior<LoggingInterceptionBehavior>(),
        () => new Interceptor<InterfaceInterceptor>()));

// ...

private const InjectionMember[] EmptyInjectionMember = new InjectionMember[0];

public InjectionMember[] ApplyInterception(params Func<InjectionMember>[] injections)
{
    if (IsInterceptionEnabled)
    {
        List<InjectionMember> injectionList = new List<InjectionMember>();

        foreach (var injection in injections)
        {
            injectionList.Add(injection());
        }

        return injectionList.ToArray();
    }

    return EmptyInjectionMember;
}

private bool IsInterceptionEnabled
{
    get
    {
        bool shouldEnableInterception;
        bool.TryParse(ConfigurationManager.AppSettings["isTracingEnabled"], out shouldEnableInterception);

        return shouldEnableInterception;
    }
}

Of course, you would need some way to trigger reconfiguration (either built-in web.config change or a FileSystemWatcher on another file if you don't want a full application recycle).

~~
Randy Levy
entlib.support@live.com
Enterprise Library support engineer
Support How-to
Jul 7, 2014 at 7:27 PM
Hi Randy,
Thanks for quick reply .This is exactly what I am looking for .
I set IsInterceptionEnabled to false during application start this is resolving the actual instance without proxy.
I set IsInterceptionEnabled to true on the fly and ConfigureContainer. This is also working as expected , unity creating the proxy instance ..until this point everything is fine
Now if I set IsInterceptionEnabled from true to false on the fly and ConfigureContainer .this is creating the proxy which is wrong ...what am doing wrong ?
Jul 8, 2014 at 3:12 AM
Unity caches the build plan so even though you "reset" the registration it does not clear the entire build plan. You could either create an entirely new container and re-register the interception or clear interception settings yourself.

Here is how to clear the interception settings using custom InjectionMembers:
    IUnityContainer container = new UnityContainer();

    container.AddNewExtension<Interception>();

    // Register without interception
    container.RegisterType<IInterceptTest, InterceptTest>();

    // Add Interception
    container.RegisterType<IInterceptTest, InterceptTest>(
        ApplyInterception(true,
            () => new InterceptionBehavior<LoggingInterceptionBehavior>(),
            () => new Interceptor<InterfaceInterceptor>()));

    // Remove Interception
    container.RegisterType<IInterceptTest, InterceptTest>(
        ApplyInterception(false,
            () => new InterceptionBehavior<LoggingInterceptionBehavior>(),
            () => new Interceptor<InterfaceInterceptor>()));
        private static readonly InjectionMember[] ClearInterception = 
            new InjectionMember[] 
            { 
                new ClearInterceptionInjectionMember() 
            };

        public static InjectionMember[] ApplyInterception(bool shouldApply, params Func<InjectionMember>[] injections)
        {
            if (shouldApply)
            {
                List<InjectionMember> injectionList = new List<InjectionMember>();

                foreach (var injection in injections)
                {
                    injectionList.Add(injection());
                }

                return injectionList.ToArray();
            }

            return ClearInterception;
        }

// ....

    public class ClearInterceptionInjectionMember : InjectionMember
    {
        public override void AddPolicies(Type serviceType,
            Type implementationType,
            string name,
            Microsoft.Practices.ObjectBuilder2.IPolicyList policies)
        {
            var buildKey = new NamedTypeBuildKey(implementationType, name);

            policies.Clear<ITypeInterceptionPolicy>(buildKey);
            policies.Clear<IInterceptionBehaviorsPolicy>(buildKey);
        }
    }

Note that if you are reconfiguring the container at runtime (e.g. calling RegisterType after startup bootstrapping) you need to ensure thread safety during the registration code (to avoid concurrent resolves while registrations are occurring).


~~
Randy Levy
entlib.support@live.com
Enterprise Library support engineer
Support How-to