Policy Injection Application Block
This page provides an overview of the Enterprise Library Policy Injection Application Block. An application block is reusable and extensible source code-based guidance that simplifies development of common logging functionality in .NET Framework applications.
Applications include a mix of business logic and crosscutting concerns, and the two are typically intermingledwhich can make the code harder to read and maintain. Each task or feature of an application is referred to as a "concern." Concerns that implement the features of an object within the application, such as the business logic, are core concerns. Crosscutting concerns are the necessary tasks, features, or processes that are common across different objectsfor example, logging, authorization, validation, and instrumentation. The purpose of the Policy Injection Application Block is to separate the core concerns and crosscutting concerns.
Developers can use the Policy Injection Application Block to specify crosscutting behavior of objects in terms of a set of policies. A policy is the combination of a series of handlers that execute when client code calls methods of the class andwith the exception of attribute-based policiesa series of matching rules that select the classes and class members (methods and properties) to which the application block attaches the handlers. Attribute-based policies rely on attributes directly applied to the members of the target class to identify those to which the application block will apply policies. The result is a mechanism for declaratively applying a chain of handlers to members of the target class instance. This chain of handlers is a pipeline.
Figure 1 illustrates a high-level view of the way the Policy Injection Application Block implements a handler pipeline for a specified member of a specified class.
Figure 1. High-level view of the way the Policy Injection Application Block implements a handler pipeline
The Policy Injection Application Block provides a mechanism for automatically applying policies to object instances; this helps developers to better manage crosscutting concerns and maximize separation of concerns and encapsulation of behavior. Developers define the set of policies for the target classes and their members through configuration of the Policy Injection Application Block or by applying attributes to individual members of the target class.
The matching rules for each policy encompass a range of capabilities for selecting classes and members, including the name of the assembly, the namespace, the type, the member name, the member signature, attributes that are applied to the member, and more.
A factory method of the Policy Injection Application Block creates a proxy for each configured class selected by the matching rules or the directly applied attributes; the method attaches the handler pipelines to each proxy and connects them to the appropriate methods and properties of a new instance of the target object. If there are no policies for the object, the application block detects this and returns the object itself instead of a proxy to that object.
The handlers within each pipeline are reusable and independent of the object. Each handler can implement a specific requirement, such as validating a property value or checking a user's authorization status. In fact, many of the crosscutting tasks regularly occurring within applications that use Enterprise Library are calls to other application blocks within the library, such as the Validation Application Block, the Logging Application Block, the Exception Handling Application Block, the Security Application Block, and the Instrumentation and Performance Counters features of the Enterprise Library Core.
The Policy Injection Application Block ships with pre-built handlers for these application blocks that speed up development when using the Enterprise Library to help manage crosscutting concerns. Developers can also create custom handlers and policies that carry out almost any required interception processing for methods and properties of their objects.
The Policy Injection Application Block provides a configurable and easy to use mechanism for applying policies to objects in order to reduce crosscutting concerns and improve object encapsulation. In particular, it makes it easy to take advantage of common features of the other Enterprise Library application blocks and core features to accomplish commonly required tasks such as validation, exception handling, logging, and more. This section describes the design and operation of the Policy Injection Application Block, showing how the interception mechanism works.
Class Hierarchy of the Policy Injection Application Block
Figure 2 illustrates the interrelationships between the key classes in the Policy Injection Application Block. This diagram also shows the relative structure and hierarchy of the objects in the set of policies for the application block when code executes the Create or Wrap method of the PolicyInjection factory class.
Figure 2. Class diagram of the Policy Injection Application Block
The Policy Injection Application Block uses .NET Framework remoting technology to perform interception and allow policies to insert handler pipelines between the client call to a method or property and the actual target object method or property. Remoting an object requires the .NET Framework to create two proxies between the client and the target object.
The first of these proxies is an instance of the __TransparentProxy class (from the System.Runtime.Remoting.Proxies namespace), which deceives all the common language runtime (CLR) code that performs casting, field access, method dispatch, and so on, into thinking that it is dealing with a local instance of the appropriate type. The second of the proxies is an instance of a class that inherits from the RealProxy class (also in the System.Runtime.Remoting.Proxies namespace). This class provides an extensibility point where you can define your own proxy to perform communication across the chosen channel to the target object.
In the Policy Injection Application Block, InterceptingRealProxy is the concrete class that inherits from the RealProxy class. The InterceptingRealProxy instance generates the handler pipeline and invokes the first handler in response to calls from the client code arriving through the TransparentProxy.
Figure 1 also shows the hierarchy of objects that implement the set of policies for the Policy Injection Application Block. The InterceptingRealProxy instance uses these to select the appropriate classes and members for which interception will apply, and to generate the handler pipeline for matching class members. The RuleDrivenPolicy instance holds information about the matching rules and handlers for a policy defined in the application configuration. The AttributeDrivenPolicy instance holds information about the set of handlers applied to target object classes and class members through directly applied attributes, for which there is no information in the application configuration.
Runtime Behavior of the Policy Injection Application Block
To understand how the application block passes client code calls to the target object at run time, you must visualize the dynamic behavior. Figure 3 illustrates how the InterceptingRealProxy invokes the first handler in the handler pipeline. Each handler invokes the next handler in the pipeline through a delegate named GetNextHandlerDelegate until the final handler in the pipeline invokes the method or accesses the property of the target object.
Figure 3. The process flows through the handler pipeline for a method call to the target object
After the target method or property accessor completes, control passes back to the previous handler in the pipeline as the Invoke method calls unwind from the run-time stack. Finally, the InterceptingRealProxy passes the return value (if any) through the TransparentProxy to the client.
The remoting mechanism in the .NET Framework defines interfaces named IMessage and IMethodCallMessage that can hold details of the message passed along the remoting channel. However, the Policy Injection Application Block defines two specific interfaces for classes that implement invocation and return messages transmitted over the handler pipeline:
- IMethodInvocation. This interface defines the structure of a message that passes the client call to the target object. It defines properties that expose the inputs and parameters of the call, the target object and target member (method or property), and the invocation context (a Dictionary). It also defines two methods that generate a message or an exception to return to the client.
- IMethodReturn. This interface defines the structure of a message that passes back from the target object to the client and contains the result of the property access or method invocation. It defines a property that exposes the output parameters, read/write properties that expose the return value and any exception for return to the client, and the invocation context (a Dictionary).
Each handler can examine and modify the values in the messages, although they must not attempt to modify the method or property accessor signature because this will generally result in remoting failures and hard to find bugs in the handler code.
Aborted Handler Exception
Figure 4 demonstrates a scenario where a handler in the handler pipeline aborts execution. In this scenario, the handler pipeline containsin execution ordera Logging Handler, an Authorization Handler, and a Validation Handler. If, as shown in Figure 4, the Authorization Handler detects an authorization failure, it simply fails to invoke the next handler in the chain. Therefore, only the series of Invoke calls already executed will unwind from the stack. This means that only the handlers that have already executed can perform their post-processing tasks.
Figure 4. The process flows through the handler pipeline when a handler aborts the method call to the target object
Also notice in Figure 4 how a handler can return an exception to the client code by adding it to the message that passes along the handler pipeline. This allows handlers earlier in the pipeline to carry out their post-processing tasks (such as, in this example, creating and writing a log message) as the Invoke stack unwinds. If, instead of passing it back through the message, a handler raises an unhandled exception, the previous handlers will not be able to execute their post-processing tasks.
The interception mechanism used by the Policy Injection Application Block depends on standard .NET Framework remoting techniques. However, in the Enterprise Library 3.1 May 2007 release, you can change the interception mechanism to one that better suits your custom requirements via configuration. For example, you may want to use a different communication channel for messages sent between handlers and the target object, or you may need to use a custom message type.
Connecting your new interception mechanism to the rest of the Policy Injection Application Block requires that you create a class that inherits from the PolicyInjector class. For configuration support, you can implement a configuration element by deriving from the InjectorData class. After you do that, you can use the Enterprise Library Configuration Console to set the Policy Injection Application Block to use your injector as the default instead of the normal remoting proxy based interception.
Additionally, this release of the Policy Injection Application Block includes the following improvements:
- Call Handler attributes are now correctly honored when they are placed on interface methods.
- An issue that could cause duplicate handlers where matching rules matched both a class and its interface is fixed in this release.
- Classes implementing COM interfaces (including those derived from System.Windows.Forms.Form) can now be intercepted.
- TraceLogEntry class is now serializable, allowing it to be used with the MSMQ Trace Listener.
The Policy Injection Application Block has been developed as a result of analyzing common enterprise development challenges and successful solutions to these challenges. However, because each application is unique, you will not find this application block suitable for every application. To evaluate this application block and determine its applicability to your projects, Microsoft suggests you dedicate at least half of a day to explore the application block. The following is a suggested evaluation approach:
- Download the Enterprise Library.
- Install the Enterprise Library and compile all application blocks and tools.
- Read the "Introduction" and "Scenarios and Goals" sections of the documentation.
- Compile and run the QuickStart samples, and read through the related "QuickStart Walkthroughs" and "Key Scenarios" sections of the documentation.
- If the application block looks like a good fit for your application, try implementing a simple use case in your application or in a throw-away prototype application using the application block.
Enterprise Library, like many patterns & practices deliverables, is associated with a community site. On this community site, you can post questions, provide feedback, or connect with other users for sharing ideas. Community members can also help Microsoft plan and test future deliverables, and download additional content such as extensions and training material.
Questions? Comments? Suggestions? To provide feedback about this application block, or to get help with any problems, please visit the Enterprise Library Community site. The community site is the preferred feedback and support channel because it allows you to share your ideas, questions, and solutions with the entire community.
Enterprise Library is a guidance offering, designed to be reused, customized, and extended. It is not a Microsoft product. Code-based guidance is shipped "as is" and without warranties. Customers can obtain support through Microsoft Support Services for a fee, but the code is considered user-written by Microsoft support staff. For more information about our support policy, see the Enterprise Library home page.