Using Interception and Policy Injection
Policy injection by a combination of Unity and the patterns & practices Enterprise Library uses a set of call handlers and the equivalent call handler attributes in conjunction with the underlying Unity interception mechanism. Interception enables you to effectively capture calls to objects and provide additional functionality to the target object by using behaviors and call handlers in the pipeline to define and manage the results of the interception. In Enterprise Library, policy injection is just one implementation of a Unity interception behavior. The PolicyInjectionBehavior captures calls to objects you resolve through the container, and applies a policy that uses call handlers and matching rules inherited from Unity to define its policy injection behavior on a per-method basis.
Typically, you will use this technique to change the behavior of existing objects, or to implement the management of crosscutting concerns through reusable handlers. You can specify how to match the target object using a wide range of matching rules, and construct a behavior which is effectively a policy pipeline that contains one or more call handlers.
Calls to the intercepted methods or properties of the target object are passed through the call handlers in the order in which you add them to the pipeline, and returned through them in the reverse order. Your call handlers can access the values in the call, change these values, and control execution of the call. For example, the call handlers might authorize users, validate parameter values, cache the return value, and, if the logic so dictates, shortcut execution so that the target method does not actually execute.
Unity enables you to specify and customize any interception behavior and also enables you to use interception with or without a container. The earlier approach to policy injection is still supported, but you can also provide policy injection by using interception behaviors.
For information on using behaviors see Behaviors for Interception.
For information on using interception without a container see the "Stand-Alone Unity Interception" section in the Using Interception in Applications topic.
This topic contains the following sections that describe using policy injection and containers with interception:
- Process Flow for Interception Using Policy Injection
- Using the Built-In Policy Injection Behavior
- Interception Policies
- Matching Rules
- Call Handlers and Policy Injection
- More Information
Process Flow for Interception Using Policy Injection
This topic describes the flow of the interception process when using policy injection in your applications.
Policy injection processes calls to objects on a per-method basis and provides additional functionality to the target object by using behaviors in the behaviors pipeline to define and manage the results of the interception. Policies are applied on a per-method basis and use call handlers and matching rules to define the policy injection behavior. As with all interception behaviors, you can use Unity policy injection interception behavior with a dependency injection (DI) container or as a stand-alone feature with no DI container. There are two basic phases to the policy injection process, flow initialization and execution time.
At initialization time, when the intercepted object is created or an existing object is wrapped for each interceptable method, policy injection has the following process flow:
- Determine which of the available policies apply to the method being intercepted. This is based on the matching rules for each policy.
- Create a handlers pipeline for the method by combining the handlers from each of the matching policies. The order of handlers in this merged pipeline is determined by the order in which the policies were specified, plus any order override specified for individual handlers.
- Add an entry to the method's handler pipeline mapping.
At execution time, when a method in an intercepted object is invoked, policy injection has the following process flow:
- The handler pipeline built for the invoked method during initialization is retrieved from the method's handler pipeline mapping.
The method's handler pipeline is invoked, which effectively inserts it into the behaviors pipeline.
Calls to other methods in the intercepted object result in the handlers pipeline for each of those objects also being inserted into the behaviors pipeline.
Using the Built-In Policy Injection Behavior
To use the built-in policy injection behavior, configure one or more objects for interception by using RegisterType and specify the PolicyInjectionBehavior with no parameters. The following extract shows how to create the instance to include in the call to RegisterType.
New InterceptionBehavior(Of PolicyInjectionBehavior)()
The result of this is that the behavior object is resolved through the container with the container effectively supplying the constructor parameters.
The built-in policy injection behavior searches the container for all policies, and applies only those that match and are executed when a method is called or a property of the target object is accessed. The appropriate call handler is then accessed. It will look for call handler attributes on the target class and apply any specified call handlers. The AttributeDrivenPolicy policy uses call handler attributes to determine which call handlers to use. Other policies are the result of setting them up with matching rules and handlers.
You do not link a policy with a target type. Instead use matching rules in each policy to select the type and members to which it will apply.
The interception mechanism's determination of which methods can be intercepted is based on which interceptor you are using, such that only virtual methods get intercepted with the VirtualMethodInterceptor and only interface methods get intercepted by an InterfaceInterceptor.
The combination of matching rules that select target classes and methods with a pipeline containing one or more call handlers provides the functionality to define interception policies. A policy is simply a set of call handlers that are assembled in a specific order and injected between the caller and the target object. Policies can be specified in the configuration of the application at design time (such as in the configuration file), configured at run time using code, or specified by attributes applied to classes and members of classes.
A rule-driven policy is one defined by either design-time or run-time configuration, and can be changed by updating the configuration. This provides a flexible approach and allows for changes to the behavior without requiring changes to the code itself.
An-attribute driven policy is defined by applying attributes that specify individual call handlers directly to classes and class members. This means that changes to the policy will require changes to the original code, and subsequent redeployment. However, it provides a more permanent approach to policy injection that cannot be changed by users or administrators at run time.
In order to specify which objects and which members (methods and properties) of these objects you want to intercept, you use matching rules. Matching rules are only used to determine which policies apply for each interceptable method. Unity includes a wide range of matching rules that you can use to identify objects in different ways. For example, you can specify the class name, the method or property name, the assembly name, the namespace, and more. You can even use wildcards for partial matches, and combine more than one matching rule in each policy definition. For details of the matching rules included with Unity, see Policy Injection Matching Rules.
If none of the matching rules is suitable for your requirements, you can create your own and use it with Unity. In addition, instead of using matching rules to apply policies, you can use call handler attributes to apply individual handlers to classes and their members. One special attribute can also be used to prevent policies from being applied to a class or to specific members of a class.
Call Handlers and Policy Injection
Design patterns such as Interception, Decorator, Chain of Responsibility, and Intercepting Filter define how you can create a graph of objects, and pass a call through the series of objects. The call passes through a series of objects, often referred to as call handlers, which can access the parameters passed to a method, or the value of a property. A common use of interception is to create a handler pipeline in order to apply a predetermined policy to objects that do not implement rules or tasks that are part of the policy. For example, you may want to validate method parameters and cache the return value to maximize performance for subsequent calls to the method. You may also want to log details of the call and authorize the caller before accessing the target method.
Instead of changing the target object to implement these functions, or writing a wrapper around the target object, you can use policy injection to inject a series of handlers into the execution pipeline based on configuration information or startup code in your application. This means that you do not have to rewrite, recompile, retest, and redeploy the original class. It also means that you can apply policies to objects for which you do not have the source code, or which you cannot modify.
Effectively, the call from the originating class is intercepted and passed through the handlers in the chain, and then on to the original target object. Every handler can access details of the call, such as the method or property name, the parameter types and values, the returned type and value (because the call returns back through the chain in the opposite direction), and other information. Depending on the pattern and your individual requirements, objects in the chain may be able to modify the parameter or return values, block the call by not passing it to the next object in the chain, or raise an exception and pass this back through the chain to the original caller.
Unity does not contain any implementations of call handlers. You will usually create these to implement the specific crosscutting concerns or functionality you require. However, Enterprise Library contains a series of prebuilt call handlers that you can use with Unity interception. These handlers use the other blocks in Enterprise Library to implement common crosscutting concerns such as logging, caching, exception handling, authorization, and validation. For information, see Enterprise Library Call Handlers.
In Unity, a behaviors pipeline is used instead of a call handler pipeline. The behaviors pipeline can have behaviors added to it and one of these can be a policy injection behavior. You can still use code from earlier versions of Unity policy injection and Unity's underlying code will package it into a behavior and add it to the pipeline. For more information see Configuration Files for Interception and Registering Interception.
For more information about using interception and policy injection with Unity, see the following topics:
- Unity Interception Techniques. This topic describes how interception works in Unity, and provides details of the different interceptors that Unity provides.
- Policy Injection Matching Rules. This topic describes in detail all of the matching rules included with Unity, and how you can use them to select classes and class members as targets for interception.
- Attribute-Driven Policies. This topic explains how you can apply attributes directly to your classes to specify interception and add call handlers to a pipeline.
- Enterprise Library Call Handlers. This topic describes the call handlers included in Enterprise Library that you can use with policy injection.
- Configuration Files for Interception in the section Design-Time Configuration. This topic describes how to configure interception support and interception policies using configuration files and other configuration sources.
- Registering Policy Injection Components in the section Run-Time Configuration. This topic describes how to configure interception support and interception policies at run time using code.
- Creating Policy Injection Matching Rules. This topic describes how to create your own matching rules if none of those provided with Unity meet your requirements.
- Creating Interception Policy Injection Call Handlers. This topic describes the design of call handlers, and how you can create your own. It explains how to handle calls within the pipeline, and how to manage exceptions and errors.
- Creating Interception Handler Attributes. This topic describes how to create attributes that apply call handlers to classes and their members. It is appropriate if you create your own call handlers.