Brent Arias
Brent Arias

Reputation: 30165

Unity Interception From Base Class

I want to declare interception to Unity for a particular base type, and have that interception be honored for all derived types automatically.

I see two different SO posts that are the same topic, but neither has the answer I'm looking for:

So I'd like to show the code I have, and see if I can get an answer specific to my scenario.

I have these classes:

public abstract class RootController
{
    [Report]
    public abstract void Action();
}

public class MyController
{
    public void Action()
    {
        Console.WriteLine("hey");
    }
}

The [Report] annotation is my own custom attribute - it indicates AOP logging should be applied to the method. I arrange for it to be used with policy-based interception as follows:

container.AddNewExtension<Interception>();

container.RegisterInstance<InjectionPolicy>(typeof(ReportAttributePolicy).AssemblyQualifiedName, new ReportAttributePolicy());

container.RegisterType<RootController>(
   new Interceptor<VirtualMethodInterceptor>(),
   new InterceptionBehavior<PolicyInjectionBehavior>()
);

The ReportAttributePolicy is my custom version of AttributeDrivenPolicy. See my Unity Interception blog post for details.

Obviously the scenario I'm trying to make work is this:

        var yup = container.Resolve<MyController>();

Even though the requested type merely derives from RootController, I would like the resolved type to be instrumented with AOP logging, per my ReportAttributePolicy.

When I execute the above code, none of the methods on my ReportAttributePolicy are executed. This means I don't have a chance to make magic happen. If I'm not dealing with an inheritance example, then it all works fine.

How do I make it work with inheritance?

Upvotes: 1

Views: 970

Answers (1)

TylerOhlsen
TylerOhlsen

Reputation: 5578

When you call container.Resolve(...), Unity looks for a configured interceptor. If there is none present, no interception is performed. This check is done on the type that was requested to be resolved. Since you called resolve on MyController and that type did not have a configured interceptor, no interception was performed. The only way around this is to register all of your controllers that derive from RootController and set an interceptor. I have included some helper methods to make this easy...

public static IUnityContainer EnableInterception<T>(this IUnityContainer container)
{
    container.EnableInterception(typeof (T));
    return container;
}

public static IUnityContainer EnableInterception(this IUnityContainer container, Type type)
{
    if (type.IsInterface)
        container.Configure<Interception>().SetInterceptorFor(type, new InterfaceInterceptor());
    else
        container.Configure<Interception>().SetInterceptorFor(type, new VirtualMethodInterceptor());
    return container;
}

public static IUnityContainer EnableInterception(this IUnityContainer container, IEnumerable<Type> types)
{
    foreach (var type in types)
    {
        container.EnableInterception(type);
    }
    return container;
}

public static IEnumerable<Type> DerivedFrom<T>(this IEnumerable<Type> types)
{
    return types.Where(t => typeof (T).IsAssignableFrom(t) && typeof (T) != t);
}

With these extensions and with the new Unity 3.0 registration by convention methods, the task of registering and enabling interception becomes pretty simple.

var controllers = AllClasses.FromLoadedAssemblies().DerivedFrom<RootController>();

container.RegisterTypes(
    controllers, 
    WithMappings.None, 
    WithName.Default, 
    WithLifetime.Transient);

container.EnableInterception(controllers);

Upvotes: 0

Related Questions