Jaa


Unity Interception for Silverlight

Retired Content

This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This page may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist.

The latest Enterprise Library information can be found at the Enterprise Library site.
The latest Unity Application Block information can be found at the Unity Application Block site.

patterns & practices Developer Center

On this page:
Unity Interception | Instance Interception - InterfaceInterceptor, TransparentProxyInterceptor, Advantages and Limitations of Instance Interception | Type Interception - Advantages and Disadvantages of Type Interception | Interception Behaviors

With the introduction of Enterprise Library 5.0 Silverlight Integration Pack, Unity Interception has now been almost fully ported to Silverlight. In this chapter, we'll discuss the features that Unity Interception provides, which scenarios it supports, and how to apply it.

Unity Interception

Unity provides a built-in mechanism for performing interception. When you register a type with Unity, you also have the option to register an interceptor, which describes how the target object should be intercepted, and one or more behaviors, which control what actions to perform when member calls are intercepted.

Basically, there are two methods for implementing interception: instance interception and type interception. Both have specific advantages and disadvantages that you'll need to be aware of.

Instance Interception

One method of interception is called instance interception, which essentially wraps a target object with a proxy that impersonates the target object. If a member call can be intercepted, it will be routed through the proxy before it reaches the target object. This is where the proxy can apply interception to those member calls. The following diagram explains in more detail how this interception process works.

Follow link to expand image

The typical occasion for using instance interception is when the client uses Unity to resolve a new instance of the target object. Unity will create both the target object and a proxy object that wraps the target object and returns the proxy to the client, rather than the target object. Any calls by the client to the proxy object are fed through a pipeline of behaviors until they reach the target object’s implementation of the invoked method. These behaviors allow you to apply custom logic before or after the member call. Please refer to the section on Interception Behaviors for more information on this pipeline of behaviors.

In Silverlight, the only way the proxy can impersonate the target object is through interfaces. The proxy will then implement the one or more interfaces as the target object (you can choose). In Unity, this is accomplished using the InterfaceInterceptor class.

Note: On the desktop versions of the .NET Framework and Enterprise Library, it is also possible for the proxy to use .NET remoting to impersonate the target object. In Unity, this is implemented using the TransparentProxyInterceptor.

InterfaceInterceptor

If you use the InterfaceInterceptor, the interceptor will automatically create a proxy object for you that implements the requested interface. The advantage of InterfaceInterceptor is the enhanced performance of the interception process, but it has as a down side in that you can only intercept the members of the requested interface.

TransparentProxyInterceptor

The TransparentProxyInterceptor uses .NET remoting to create a proxy. In order to be able to do that, the target object needs to derive from MarshalByRefObject. This method has as an advantage that you can intercept any member call to the target object, but these calls will be a lot slower than regular member calls. Since .NET remoting is not available in Silverlight, this option is only available in the desktop version of the .NET Framework and Enterprise Library 5.0.

Note

The TransparentProxyInterceptor does not work properly if you hide inherited members using the new keyword. If you use the new keyword for a member, effectively you'll create two members with exactly the same name and signature. The remoting proxy then has no way to distinguish between them and will throw an InvalidOperationException.
Using the new keyword is generally not recommended because it can cause undesired side effects when you use polymorphism, but if you find that you really need to do so, you should be aware that you cannot use the TransparentProxyInterceptor.

Advantages and Limitations of Instance Interception

A major advantage of using instance interception, compared to type interception, is that it is possible to apply interception to existing object instances. While it is possible to resolve newly created intercepted objects from the Unity container, it is also possible to apply this type of interception to already created instances. This is especially useful if you are not able to construct the target objects yourself, for example, but must rely on a factory method to instantiate the objects.

A limitation of instance interception is the fact that only external calls to the object, which go through the proxy, can be intercepted. So if the target object calls a method on itself, the call will not be intercepted. That sort of interception can only be provided by type interception.

For an object to be interceptable using instance interception, it either has to implement an interface and use the InterfaceInterceptor, or derive from MarshalByRefObject and use the TransparentProxyInterceptor.

Type Interception

Type interception does not create a separate proxy, but creates a derived object from the target object. Type interception can intercept method calls by overriding virtual members. The overridden virtual member can then intercept the member call and apply custom interception logic before it calls the original base member. The following diagram shows type interception in more detail:

Follow link to expand image

When the application resolves the required type through the Unity container, the Unity interception container extension creates the new derived type and passes it, rather than the resolved type, back to the caller. Because the type passed to the caller derives from the original class, it can be used in the same way as the original class. The client simply calls the target object, and the derived class will pass the call through the behaviors in the pipeline just as is done when using instance interception.

Because type interception uses inheritance, this method of interception can only intercept members that have been marked as virtual. The interception mechanism will dynamically create a base class for the target object and override the methods that have been marked as virtual.

Advantages and Disadvantages of Type Interception

Type interception uses inheritance to merge both the proxy and the target object into a single object instance. The advantage of this approach, compared to instance interception, is that internal member calls will also be intercepted.

Type interception is a bit more invasive than instance interception. You can only use type interception when you create a new instance of a type. Contrary to instance interception, it's not possible to use type interception on a previously created object instance. So if you cannot create the target object yourself, then you cannot apply type interception.

Another limitation of type interception is that you can only intercept members that you have explicitly marked as virtual. This means that you may need to modify the target class somewhat to apply interception.

Interception Behaviors

You can add custom logic to an intercepted member call by adding interception behaviors to the interceptor. An interception behavior is a class that implements the IInterceptionBehavior interface. You can register more than one behavior to an interceptor. These behaviors are chained together following the Chain of Responsibility pattern. When a call is intercepted, each behavior object executes its own logic and will then call the next behavior. The last behavior will then invoke the actual object. The result of the call (for example a return value or an exception) will be passed back through the chain of behavior objects until it reaches the calling object again.

Follow link to expand image

If you don't wish the target object (or the next behavior) to be called, you can prevent that from happening by not invoking the next behavior in the chain. There are several scenarios in which this is useful. For example, when you want to validate the input of a method call, and the input is not valid, you can prevent the target method from being called with invalid data and returning an exception. Another example would be when you'd like to cache the results of a method call. The caching behavior can check if the results of this particular method call are already present in the cache. If so, it can just return the cached result and avoid the target method being called.

For more information on implementing a custom behavior, please refer to the section called Creating a Custom Interception Behavior.

Next Topic | Previous Topic | Home

Last built: July 8, 2011