Using Interception with Unity
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 Unity Application Block information can be found at the Unity Application Block site. |
Interception is a design pattern that is designed for cross-cutting concerns, issues that cut across the entire software. Unity provides support for interception through the Interception container extension.
In general, there are two kinds of logic written in most applications; these types of logic are often referred to as business logic and cross-cutting concerns. Business logic is what everyone thinks of when referring to the actual code that performs the functions of the application, such as calculating pay rates and managing inventory. You would expect that this would be the majority of the application, but when you look at many applications you see a lot of the second kind of code that is dedicated to managing infrastructure instead of actually performing the specific function of the application. In some methods, the actual purpose is completely buried under security checks, input validation, logging, and so on. These are known as cross-cutting concerns, because they appear throughout an application in ways that cannot be completely encapsulated in one spot. Because of this, you must repeatedly make the same calls. This repetition makes the code more difficult to maintain.
When you look at many of these cross-cutting concerns, you can recognize a pattern. Many of them happen only at either the start or the end of a method. You log when a method is called. You check your inputs for validity before processing. You handle exceptions after the method fails. This leads to a different approach to implementing cross-cutting concerns. You can put some special handling before or after method calls to handle the cross-cutting concerns, get the code out of the methods, and enhance its maintainability. The Unity Interception extension lets you do just that.
Note
The Unity Interception extension provides a subset of aspect-oriented programming (AOP).
Unity Interception Mechanism
The interception mechanism is based around three basic concepts: matching rules, call handlers, and interceptors. Matching rules are simple but flexible objects that determine which methods should have extra handling applied. Call handlers are objects that actually implement the cross-cutting concerns. They can run before or after the method. They can modify method parameters or return values. They can even stop the method from being called at all or call it multiple times. The matching rules and call handlers are grouped together into interception policies. The interception policy uses the matching rules to define which methods get intercepted and uses the call handlers to define what processing to perform on the intercepted object.
For more information, see Configuring and Using Matching Rules,Creating a New Matching Rule, Creating a New Handler, and Configuration Support for Interception.
Policies determine what happens when a method is intercepted, and interceptors determine how methods are intercepted. Unity interceptors will, when configured in the container, enable you to intercept method calls and attach call handlers to the intercepted methods. Policies determine which call handlers are placed in the interception pipeline for each method.
Note
When using stand alone Unity, you must create your own call handlers. For more information, see Creating a New Handler. You can also use Enterprise Library's Policy Injection Application Block, which includes a number of call handlers.
All policies supply call handlers to the interceptors when wiring up interception on an object. The policies are either rule driven or attribute driven. The matchingRules are specific to RuleDrivenPolicies. The AttributeDrivenPolicy determines which methods should be intercepted based on methods' attributes. For information about attribute handlers, see Creating a New Handler Attribute.
Using the Unity Interception extension provides the following advantages:
- The infrastructure code can be removed from your method bodies; this makes the code much more readable.
- The interception policy and interceptor settings can be specified in the configuration; this enables you to change behavior without recompiling or even changing the code.
- Facilitated separation of concerns that results in a more flexible, loosely coupled application.
Instance and Type Inteceptors
The two styles of interception are instance interception and type interception.
Instance Interceptors
Instance interceptors use a separate proxy object between your code and your target object. Using interception, you make a call on the proxy object instead of directly calling the target object. The proxy invokes the various call handlers, and then it forwards the call to the target object. Different implementations of instance interceptors can have different constraints. Instance interceptors have the following characteristics:
- They can intercept objects created by the container.
- They can intercept objects not created by the container.
- They can only be used with interfaces or marshal-by-reference objects unless they are a TransparentProxyInterceptor, which works on interfaces and marshal-by-reference objects.
- Instance interceptors can be used to intercept on only one interface of an object unless they are a TransparentProxyInterceptor, which can be used to intercept several interfaces.
Type Interceptors
Type interceptors create a new type that inherits from the target type. This new type is then instantiated instead of the original type you requested. It overrides all the virtual methods on your target type. There is only one object instead of two as with instance interceptors. Type instance interceptors have the following behaviors:
- There is only one object created.
- They have full type compatibility because they are derived from the target type.
- They are able to intercept ojects only at creation and cannot intercept existing instances.
- They can only intercept virtual methods.
The Unity Interceptors
The Unity Interception extension ships with two instance interceptors and one type interceptor. The following table lists Unity's interceptors and their description.
Type |
Description |
Use |
---|---|---|
TransparentProxyInterceptor |
An instance interceptor. The proxy is created by using the .NET TransparentProxy/RealProxy infrastructure. |
When the type to intercept is a MarshalByRefObject or when only methods from the type's implemented interfaces need to be intercepted. |
InterfaceInterceptor |
An instance interceptor. It can proxy only one interface on the object. It uses dynamic code generation to create the proxy class. |
When resolving an interface mapped to a type. |
VirtualMethodInterceptor |
A type interceptor. It uses dynamic code generation to create a derived class that gets instantiated instead of the original, intercepted class and to hook up the call handlers. |
When only virtual methods need to be intercepted. |
Selection of a specific interceptor depends on your specific needs, because each one has various tradeoffs. The following table summarizes the three interceptors and their advantages and disadvantages.
Type |
Advantages |
Disadvantages |
---|---|---|
TransparentProxyInterceptor |
Can intercept all methods of the target object (virtual, non-virtual, or interface). |
The object must either implement an interface or inherit from System.MarshalByRefObject. If the marshal by reference object is not a base class, you can only proxy interface methods. The TransparentProxy process is much slower than a regular method call. |
InterfaceInterceptor |
Proxy supports casting to all the interfaces or types of the target object. |
It only intercepts methods on a single interface. It cannot cast a proxy back to target object's class or to other interfaces on the target object. |
VirtualMethodInterceptor |
Calls are much faster than the TransparentProxyInterceptor. |
Interception only happens on virtual methods. You must set up interception at object creation time and cannot intercept an existing object. |
You can set up a container for interception by using the Unity interception configuration elements. UnityConfigurationSection is the type name and by convention the element name is <unity>.
For information about using Enterprise Library and Policy Interception Application Block handlers, search the Enterprise Library Help file for "Call Handlers" or see Configuring and Using Pipeline Handlers on MSDN.
For more information about matching rules, see Configuring and Using Matching Rules.
The following code example uses the <UnityConfigurationSection> from a configuration file to configure a container for interception.
public static void UnityWithConfigInterception()
{
IUnityContainer container = new UnityContainer();
UnityConfigurationSection config = ConfigurationManager.GetSection("unity") as UnityConfigurationSection;
config.Containers.Default.Configure(container);
DoYourCode(container.Resolve<AccountManager>());
}
'Usage
Public Shared Sub UnityWithConfigInterception()
Dim container As IUnityContainer = New UnityContainer()
Dim config As UnityConfigurationSection = ConfigurationManager.GetSection("unity") as UnityConfigurationSection
config.Containers.Default.Configure(container)
DoYourCode(container.Resolve(Of AccountManager)())
End Sub
For more information about interceptor configuration, see Configuration Support for Interception.