Adding interception with existing registration

In this case, my application is passed to me already initialized UnityContainer

, on which the type was registered, which boils down to the following:

container.RegisterType<IService>(new InjectionFactory(c => new Service()));

      

What I need to do is add an interceptor ServiceInterceptor

to the registration IService

. I suppose the obvious answer is: do it by running the second one RegisterType<IService>

and using the interceptor as the inserts. However, re-creating the provided factory injection and delegate as described below is unfortunately not possible. The operation is new Service()

not available to me at the moment.

container.RegisterType<IService>(
    new InjectionFactory(c => new Service()),
    new Interceptor<InterfaceInterceptor>(),
    new InterceptionBehavior<ServiceInterceptor>());

      

So: I am looking for a way to add additional injection members to the existing one ContainerRegistration

.

// 1. Get the current container registration
var containerRegistration = container.Registrations
    .First(cr => cr.RegisteredType == typeof(IService));

// 2. Is this even possible?
ApplyInterception(
    containerRegistration,
    new Interceptor<InterfaceInterceptor>(),
    new InterceptionBehavior<ServiceInterceptor>());

// 3. Profit!

      

+3


source to share


1 answer


You can register the type as a named registration first (using InjectionFactory), and also provide a default (no name) registration that only allows named registration:

container.RegisterType<IService>("original",
                      new InjectionFactory(c => new Service()));
container.RegisterType<IService>(
                      new InjectionFactory(c => c.Resolve<IService>("original")));

      

So, you can resolve IService

as usual. However, you should now be able to replace the default registration while retaining the original named registration. This way you can get around your problem where you cannot re-register IService

due to the factory operator not being available at that point.

With this approach, at a later stage, you can override the default registration IService

with where the interception is registered and still use the original named registration to resolve the instance:

container.RegisterType<IService>(
    new InjectionFactory(c => c.Resolve<IService>("original")),
    new Interceptor<InterfaceInterceptor>(),
    new InterceptionBehavior<ServiceInterceptor>());

      

If you allow now IService

, you will still use the original factory method c => new Service()

as it allows the "original" named registration, but this time yours also applies ServiceInterceptor

.

I created this fiddle so you can check out a complete working example.


There is a second approach using Policy Injection . (See section "Enabling Policy" in msdn ).

First set up your type as usual, but leave the door open to use Policy Injection:



container.RegisterType<IService>(
    new InjectionFactory(c => new Service()),       
    new InterceptionBehavior<PolicyInjectionBehavior>(),
    new Interceptor<InterfaceInterceptor>());

      

At this point, your service registers with no interception applied. However, in the future, you can add a policy injection rule, for example, corresponding to the type of your service type, which adds an interception:

container.Configure<Interception>()
    .AddPolicy("yourInterceptor")
    .AddMatchingRule<TypeMatchingRule>
        (new InjectionConstructor("MyNamespace.Service", true))
    .AddCallHandler<ServiceInterceptorHandler>(
        new ContainerControlledLifetimeManager(),
        new InjectionConstructor(),
        new InjectionProperty("Order", 1));

      

Now, if you allow IService

, the interception logic will be applied in ServiceInterceptorHandler

(this class is basically the same ServiceInterceptor

in the first approach, but implements ICallHandler

instead IInterceptionBehavior

)

Check the example in this script again


Taking a look at both options, I personally feel more comfortable with the first approach, avoiding the overhead of the respective rules.

The first approach will also allow you to easily disable interception entirely by re-enabling logging IService

, saving you the overhead of interceptors if you want it to be disabled completely. (Both approaches allow you to implement a property WillExecute

of the interceptor / handler classes, but you still have the overhead of interceptors). You can do it using policy injection, but you need a different middleware call handler, see this post

However, with the second approach, you can apply this solution to multiple classes using appropriate rules (for example, all classes in a namespace or all classes whose name matches a certain pattern, etc. You can take a look at the corresponding rules here )

In the end, you will need to decide which one is right for you. (and there may be other approaches, I wish they were posted!)

+3


source







All Articles