Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Register same Unity interception & call handler for all registered types

I have an ICallHandler that I want to register with all of my Unity container instances.

For example, take the following handler:

public class ProfilerHandler : ICallHandler
{
    public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
    {
        //start timer
        IMethodReturn methodReturn = getNext()(input, getNext);
        //stop timer
    }

    public int Order
    {
        get; set;
    }
}

And the following IoC container constructor:

public class IoCContainer : UnityContainer
{
    public IoCContainer()
    {
        this.RegisterType<IUserService, UserService>(new ContainerControlledLifetimeManager());
        this.RegisterType<IRepository<User>, UserRepository>(new ContainerControlledLifetimeManager());
    }
}

All I want to do is register this handler with all of these types.

I can do this w/ some pretty verbose code:

public class IoCContainer : UnityContainer
{
    public IoCContainer()
    {
        this.AddNewExtension<Interception>();

        this.RegisterType<IUserService, UserService>(new ContainerControlledLifetimeManager()).Configure<Interception>().SetInterceptorFor<IUserService>(new InterfaceInterceptor());
        this.RegisterType<IRepository<User>, UserRepository>(new ContainerControlledLifetimeManager()).Configure<Interception>().SetInterceptorFor<IRepository<User>>(new InterfaceInterceptor());
    }
}

But not only do I have to write the same interception code on all of my type registrations (imagine if I have 100+ type registrations), but I also must include a HandlerAttribute on every interface (again, not good if I have 100+ interfaces to apply this to).

Is this my only option, or is there a way to do this at the container level to avoid having to apply this to each individual type registration & interface?

like image 800
Jerad Rose Avatar asked Jul 09 '13 21:07

Jerad Rose


1 Answers

Unity 3 provides registration by convention which could help in this scenario:

IUnityContainer container = new UnityContainer();

container.AddNewExtension<Interception>();

container.RegisterTypes(
    AllClasses.FromLoadedAssemblies().Where(
        t => t.Namespace == "My.Namespace.Services"),
    WithMappings.MatchingInterface,
    getInjectionMembers: t => new InjectionMember[]
    {
        new Interceptor<InterfaceInterceptor>(),
        new InterceptionBehavior<MyBehavior>()
    });
}

You could combine the above with Policy Injection to use matching rules to wire up your call handler. That way you could use a variety of matching rules instead of (or in combination with) attributes to determine which call handlers go with which classes/methods.

container.RegisterTypes(
    AllClasses.FromLoadedAssemblies().Where(
        t => t.Namespace == "My.Namespace.Services"),
    WithMappings.MatchingInterface,
    getInjectionMembers: t => new InjectionMember[]
    {
        new InterceptionBehavior<PolicyInjectionBehavior>(),
        new Interceptor<InterfaceInterceptor>(),
    });
}

container.Configure<Interception>()
    .AddPolicy("profiler")
    .AddMatchingRule<AssemblyMatchingRule>(
        new InjectionConstructor(
            new InjectionParameter("My.Namespace.Services")))
    .AddCallHandler<ProfilerHandler>(
        new ContainerControlledLifetimeManager());

Unity 2 also supports Policy Injection.

An alternative to the registration by convention would be to write a Unity Container Extension to perform the wiring up of interception during registration.

like image 131
Randy supports Monica Avatar answered Nov 12 '22 19:11

Randy supports Monica