Can anyone please explain how injecting addtional interfaces works?

Sep 18, 2010 at 1:52 PM
Edited Sep 18, 2010 at 2:09 PM

amendment: I've just noticed that ctavares mentioned in another post back in July that interface injection is "a highly advanced case and if you don't know why you'd use it, you don't need it and can ignore it. :-)". Fair enough. However I still feel that my particular question is a different one from the one previously posted and hence valid. I think that it would be good for us to know how to use this functionality.

I'm trying to "inject" an additional interface into an intercepted object. I've successfully resolved an object and if I check to see if the interface has been injected, it has, but it's never implemented (which makes sense I suppose). how do i implement an "injected" interface?

e.g.

            IUnityContainer c = new UnityContainer().LoadConfiguration();
            IFoo x= c.Resolve<IFoo>();
            x.DoFoo();
            var doYouBar = x as IBar;
           
doYouBar != null returns true BUT

((IBar)x).DoBar() returns

System.NotImplementedException was unhandled
  Message="Additional interfaces do not have an implementation."
  Source="Unity_ILEmit_InterfaceProxies"
  StackTrace:
       at DynamicModule.ns.Wrapped_ILogger_676ab7e076db4d0680198c8885428900.IBar.DoBar()
  InnerException:

this makes sense because i've just injected an interface - not an implementation of that interface...where/how is that done? does it have something to do with GetRequiredInterfaces?

Sep 19, 2010 at 8:00 AM

As you've discovered, all the AdditionalInterface API or config element does it make sure the proxy includes the interface, it doesn't actually provide an implementation. The implementation itself is provided by a custom interception behavior, which you'll need to write. It needs to detect when a method is called on the interface (typically by looking at the MethodInfo object passed into the invoke call) and then do, well, whatever you want it to.

Typically, you don't need to use AdditionalInterfaces. This is because most behaviors are written to implement a specific interface or interfaces, and they know what they are at compile time. That's what the RequiredInterfaces property is for - it tells the proxy generation "if you're including this behavior, add these interfaces too." It's nice and self contained. There are a small class of behaviors, however, that DON'T know at compile time, or even at proxy generation time, which interfaces they're implementing. Typically this is because they work off some other configuration. A mock object framework is the typical example here. If you've written such a behavior, then the users of that behavior need to tell the interception system, through the additional interfaces, which interfaces to add, since the behavior itself cannot.

This is the heart of my "if you don't know you need it, you don't need it" comment.

 

Sep 19, 2010 at 8:45 PM

Thank you very much for your answer. I think I understand, but with a little understanding inevitably comes more questions (sorry!).

For clarity's sake could you please explain:

  • the difference between an interceptionBehavior and a callHandler - they seem to do very similar things. is the behavior more for a specific type whereas handlers are for matching >1 type?
  • as stated in an earlier post, i've injected the interface - where (i.e. what class that the behavior has reference to) do i implement that interface? 

So far I really like Unity but there is so much to learn!

 

Sep 20, 2010 at 6:02 PM

The difference between callhandlers and behaviors is mainly historical.

In the beginning, there was the Policy Injection block. Handed down from Mount Sinai... no, wait, different story..

Basically, when we originally wrote PIAB, it was based around the concept of call handlers. These are objects that implement "aspects" and are invoked based on matching rules that check the method being called to see if it's a candidate for the aspect or not.

Behaviors, are, essentially, the exact same thing - an implementation of an "aspect" that can intercept a call or the return value from that call. In fact, if you look at the type definitions for call handlers and behaviors, there's essentially identical. So what's the difference?

There's one subtle but very important difference here. Remember my statement "... are invoked based on matching rules that check the method being called ..."? Behaviors have NO matching rules involved - they always run for every call on the intercepted object, period. If the behavior only works when called on particular methods, then the behavior author is responsible for doing the checking inside the Invoke method to determine if it's appropriate to run or not.

This difference is the reason we implemented two separate abstractions. CallHandlers are written assuming they just run; that assumption isn't valid in the context of a behavior. We felt it was safer to have two different but similar types to make the author and user aware of the difference in semantics.

This "always runs" semantic gives behaviors one piece of power that call handlers don't have - the ability to implement methods that the underlying object doesn't implement itself. Which was the whole point - to get the ability to add interface implementations through the interception mechanism. This was a feature I wanted from the start of PIAB, but couldn't get in there until Entlib 5.

So I hope this helps explain the difference.

As for how to implement the interface, basically you create a class that implements IInterceptionBehavior. Inside the implementation of the Invoke method, check the MethodInfo on the input (input.MethodBase) to see if it's one of the methods on the interface you're implementing, and if it is, well, do whatever you want. Note the the behavior doesn't need to actually implement the interface in question (that is, have the interface on it's class declaration) in order to provide the implementation of the methods. It's completely dynamic and done at runtime. For an example that does this, see the documentation on interception on MSDN.

Hope this helps,

-Chris

 

 

Sep 22, 2010 at 10:08 AM
Edited Sep 22, 2010 at 11:16 AM

Excellent. That's precisely the sort of information I was after.

What does WillExecute actually do? How can I leverage it's functionality? I don't see how I could hook into it for conditional processing as it's called before GetRequiredInterfaces and Invoke.

Speaking of which, what consumes/calls GetRequiredInterfaces? I'm still trying to understand exactly what this method does. This didn't really clarify it for me!

I'll play around with some of the ideas you've given me and I'll ask more questions if they arise? As always, thanks for the good info!

 

Sep 22, 2010 at 6:11 PM

GetRequiredInterfaces and WillExecute are called by the interceptor. When you say new Interceptor<Some Type Here>(), that's the interceptor, and it's responsible for creating the proxy/derived type used to actually run the interception.

WillExecute is a flag used by the interceptor to decide if it should do anything. If you've configured a bunch of behaviors, but none of them will actually do anything, then there's no reason to build a proxy at all. This is currently only used by the policy injection behavior. You'll need to pass in additional information to your behavior so that it knows what type it's being used on, or any contextual information, and that's when you can decide if WillExecute should be true or false.