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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With