Introducing the Policy Injection Application Block

Introducing the Policy
Injection Application Block
Agenda
 Enterprise Library 3.0 Introduction
 Policy Injection Motivation and Goals
 Policy Injection Application Block Architecture
 Call Handlers and Matching Rules
 Extending the PIAB
 Summary
Enterprise Library 3.0: New Features At a
Glance
 New application blocks
• Validation Application Block
• Policy Injection Application
Block
 Improvements to existing
application blocks
• Data Access Application
Block
• Logging Application Block
 .NET Framework 3.0
integration
• Logging, Exception
Handling and Validation
Application Blocks
 Configuration
improvements
• Visual Studio-integrated
configuration tool
• Environmental Overrides
• Manageable
Configuration Source
 Automation
• Application Block
Software Factory
• Strong Naming Guidance
Package
Enterprise Library 3.0 Application Blocks
Data
Access
Caching
Logging
Core
Cryptography
Config
Helpers
& Design
Instrumentation
Exception
Handling
Object
Builder
Security
Policy Injection
Validation
Agenda
 Enterprise Library 3.0 Introduction
 Policy Injection Motivations and Goals
 Policy Injection Application Block Architecture
 Matching Rules and Call Handlers
 Extending the PIAB
 Summary
Context
 Applications include a mix of business logic and
cross cutting concerns
 Cross cutting concerns include security, state
management and operational
• Authorization, logging, caching, transaction management,
etc.
 Both types of logic are necessary, but each have
unique characteristics
• Business logic is highly contextual and often not reusable
• Cross cutting concerns are often applied consistently across
layers and applications
Mixing Business and Cross-Cutting
Concerns
 Traditionally, business logic and cross-cutting
concerns are mixed together in code
• Even if a shared component or application block is
used, it is still generally called from code
 This can lead to
• Code that is hard to read and maintain
• Duplicated code
• Inconsistent behavior
Sample Method
Customer GetCustomerById(int id)
{
if (id < 0) throw new ArgumentException("Invalid Customer Id");
Customer customer = HttpContext.Current.Cache.Get(id.ToString()) as Customer;
if (customer != null)
return customer;
try
{
Database db = DatabaseFactory.CreateDatabase("CRM");
using (IDataReader reader = db.ExecuteReader("spGetCustomerById", id))
{
if (reader.Read())
{
customer = new Customer(id, reader.GetString(0), reader.GetString(1));
HttpContext.Current.Cache.Add(id.ToString(), customer, null,
DateTime.Now.AddMinutes(1), Cache.NoSlidingExpiration, CacheItemPriority.Normal, null);
return customer;
}
}
return null;
}
catch (Exception ex)
{
if (ExceptionPolicy.HandleException(ex, "Data Policy")) throw;
return null;
}
}
Policy Injection Application Block Goals
 Separate cross-cutting concerns from business logic
• Use interception and injection to apply policies at runtime
 Allow policies to be defined declaratively, using
configuration or attributes
• At a coarse- or fine-grained level
 Make it easy to integrate Enterprise Library
application blocks into policies
• Validation, Logging, Authorization, Exception Handling,
Caching, Performance Counters
 Design for loose-coupling and extensibility
Sample Method with Policy Injection
[ValidationCallHandler]
[CachingCallHandler(0, 1, 0)]
[Tag("Data Access")]
Customer GetCustomerById(
[RangeValidator(0, RangeBoundaryType.Inclusive, 0, RangeBoundaryType.Ignore)] int id)
{
Database db = DatabaseFactory.CreateDatabase("CRM");
using (IDataReader reader = db.ExecuteReader("spGetCustomerById", id))
{
if (reader.Read())
{
return new Customer(id, reader.GetString(0), reader.GetString(1));
}
}
}
Agenda
 Enterprise Library 3.0 Introduction
 Policy Injection Motivation and Goals
 Policy Injection Application Block Architecture
 Call Handlers and Matching Rules
 Extending the PIAB
 Summary
Policy Injection Application Block Basics
 Policy Injection Application Block provides a factory
for creating or wrapping policy-enabled objects
 If policies are defined in attributes or configuration, a
proxy is returned in lieu of the real object
 When calling policy-enabled members, a handler
pipeline is executed before and after the real member
is called
 Each handler can access the data going in and out of
the call
Policy Injection Application Block Basics
 Normally, each handler will implement a crosscutting concern before passing control to the next
handler (or the target)
 A handler may also choose to abort the pipeline if
deemed appropriate
Policies
 The definition of which handlers should execute
for which objects and methods is called a policy
 There are two types of polices:
• Configuration-based policies
• Attribute-based policies
Configuration-based Policies
 A configuration-based policy consists
of
• A set of matching rules
• A pipeline of handlers
 Matching rules are predicates that
specify which members the policy
should apply to
• For example, everything in the
GlobalBank.BusinessLogic
namespace, or all members returning a
BankAccount
• Multiple matching rules are ANDed
together
 The handler pipeline specifies the
ordered list of handlers that will
execute if the matching rules pass
 More than one policy may apply to
any given member
• They will be applied in the order
specified in configuration
Attribute-based Policies
 An attribute-based policy consists of a set of call
handlers applied directly to objects and members
using custom attributes
• Matching rules are not used
 Attributes are discovered first on types, then on
members, and applied in order of discovery
• Order of discovery of multiple attributes applied on the same
element cannot be guaranteed
 Attribute-based policies are always applied before
configuration-based policies
[CachingCallHandler(0, 1, 0)]
[LogCallHandler(LogBeforeCall = true, LogAfterCall = false,
BeforeMessage = "About to call the method")]
public int DoSomething(string input)
{
///
}
Disabling Policies
 Both configuration- and attribute-based policies
can be disabled for a given type or member
 Use the [ApplyNoPolicies] attribute to prevent
policies being applied
 Useful for methods that are performance critical,
need no cross-cutting concerns or implement
concerns differently
Interception and Injection
 In order for policies to execute when a method is
called:
• Configuration- or attribute-based policies must apply to
the member
• The instance must be created or wrapped using the
PolicyInjection factory
• The target object must be interceptable
▪ Requirements depend on the chosen injection mechanism
• Method must be called via the proxy returned from the
PolicyInjection.Create/Wrap methods, not directly on
the object
Creating or wrapping objects
 Objects must be created or wrapped with the
PolicyInjection class for policies to apply
 Even if no policies apply now, you may want to
create objects this way to allow policies to be
added in the future
• Performance impact is very low if no policies apply
MyClass1 object1 = PolicyInjection.Create<MyClass>();
MyClass2 object2 = PolicyInjection.Create<MyClass>(param1, param2);
IMyInterface object3 = PolicyInjection.Create<MyClass3, IMyInterface>();
MyClass1 object4 = new MyClass();
MyClass1 object4proxy = PolicyInjection.Wrap<MyClass1>(object4);
IMyInterface object5 = new MyClass3();
IMyInterface object5proxy = PolicyInjection.Wrap<IMyInterface>(object5);
Interception Requirements
 The requirements for intercepting objects and
members depends on the chosen injection
strategy
 The PIAB ships with a Remoting Proxy injection
strategy
• Can be replaced by alternative methods
 The Remoting Proxy Injection requires:
• The class derive from MarshalByRefObject, or
• The class implement any interface, with intercepted
calls made through that interface
Calling Policy Injected Members
 Calling policy injected members is no different to calling
any other member
• The caller can’t even tell if policies exist or not
 Policies do not alter the method signature
• Although they may alter the behavior
 Caller just calls a method and gets a return result or
exception
• Caller doesn’t know if result came from the method or a handler
BankAccount account = PolicyInjection.Create<BankAccount>(accountId);
try
{
account.Withdraw(amount);
}
catch (Exception ex)
{
// do something
}
Agenda
 Enterprise Library 3.0 Introduction
 Policy Injection Motivations and Goals
 Policy Injection Application Block Architecture
 Call Handlers and Matching Rules
 Extending the PIAB
 Summary
Supplied Handlers
 PIAB ships with six handlers
• Validation Handler
• Logging Handler
• Authorization Handler
• Exception Handling Handler
• Caching Handler
• Performance Counter Handler
 Most are shims over other Enterprise Library
application blocks
Validation Handler
 Validates parameters to a method, using the
Validation Application Block
 Validation rules can be defined
• As rule sets defined on parameter types, using either
attributes or configuration
• By applying validation attributes directly on the method
parameters
 If validation fails, an ArgumentValidationException
is thrown, and the method is not called
• Exception contains the ValidationResults from the
validation call
Logging Handler
 Writes a log entry before and/or after the method is
called, using the Logging Application Block
 Uses a TraceLogEntry which contains additional
properties related to the method call
 Handler may be configured to log additional data,
including:
• Call Stack
• Parameter Values
• Return Value or Exception
• Call execution time
 Log Categories are configurable and may include
tokens such as {method} and {type}
Authorization Handler
 Uses a Security Application Block Authorization
Provider to determine if the current user is authorized
to perform an operation
 Current user is determined from the thread principal
 Handler is configured with
• The name of the Authorization Provider instance to use
• The name of the Operation, which can include tokens such
as {type} and {method}
 If authorization fails, an
UnauthorizedAccessException is thrown, and the
method is not called
Exception Handling Handler
 Executes after a method is called
 Processes any exceptions thrown by the method
using the Exception Handling Application Block
 Handler is configured with the name of the
Exception Policy to use
 After processing, the handler will throw either the
original or the new exception back to the caller,
based on the exception policy definition
 Exceptions may only be swallowed for void
methods
Caching Handler
 Uses the System.Web.Cache to cache method
return values, keyed off the method signature and
input parameters
• Keys are generated using GetHashCode
 Handler is configured with a TimeSpan indicating
how long return values should be cached
 Before the method is called, the handler checks if a
value is in the cache for the set of inputs
• If so, the cached return value is returned, instead of calling
the method.
• If not, the method is called and the return value is cached for
future use
Performance Counter Handler
 Increments a number of performance counters that
provide useful metrics around use and performance
 Handler can be configured to specify which counters
and instances to use
 Available counters include
• Total number of times the method is called
• Rate of calls (per second)
• Average call duration
• Number of exceptions thrown
• Rate of exceptions thrown (per second)
Supplied Matching Rules
 PIAB includes a number of matching rules that test
members against static metadata:
• Assembly Matching Rule
• Custom Attribute Matching Rule
• Member Name Matching Rule
• Method Signature Matching Rule
• Namespace Matching Rule
• Parameter Type Matching Rule
• Property Matching Rule
• Return Type Matching Rule
• Tag Attribute Matching Rule
• Type Matching Rule
Effective Policy Viewer
 While the PIAB offers many benefits, separating
business code from cross cutting concerns can also
create confusion
• Complete behavior cannot be determined only by looking at
code
 To take away the mystery, p&p provides the Effective
Policy Viewer
 This application shows which policies and handlers
(configuration and attribute-based) will apply to which
members in which order
 Tool can be downloaded from
http://codeplex.com/entlib
Agenda
 Enterprise Library 3.0 Introduction
 Policy Injection Goals
 Policy Injection Application Block Architecture
 Call Handlers and Matching Rules
 Extending the PIAB
 Summary
Extensibility points
 The Policy Injection Application Block is designed
to be extended
 Defined extensibility points are:
• Matching Rules
• Handlers
• Injectors
 Other changes are possible by modifying source
code
Building Custom Matching Rules
 Build a new class implementing IMatchingRule
 Create necessary constructors and fields for
configurable properties
 Implement Matches
• bool Matches(MethodBase member)
 Build a runtime configuration class, if you want
strongly-typed configuration, or use
CustomMatchingRuleData
 Add the ConfigurationElementType attribute to
the class, pointing to the runtime configuration
class
Building Custom Handlers
 Build a new class implementing ICallHandler
 Create necessary constructors and fields for configurable
properties
 Implement Invoke
• IMethodReturn Invoke(IMethodInvocation input,
GetNextHandlerDelegate getNext)
• Perform any pre-processing
• Call the next handler using getNext().Invoke(input, getNext);
• Perform any post-processing
• Return the desired return value or exception
 Build a runtime configuration class, if you want strongly-typed
configuration, or use CustomCallHandlerData
 Add the ConfigurationElementType attribute to the class,
pointing to the runtime configuration class
Agenda
 Enterprise Library 3.0 Introduction
 Policy Injection Motivations and Goals
 Policy Injection Application Block Architecture
 Call Handlers and Matching Rules
 Extending the PIAB
 Summary
Summary
 The Policy Injection Application Block is about
separating business logic from cross cutting concerns
 Cross cutting concerns are applied using policies,
comprising of matching rules and a handler
pipeline
 Each handler can perform logic before or after a
method call
 Policy-enabled objects are created with a factory that
returns a proxy wired up to the handler pipeline
 Used wisely, this application block can improve
clarity, maintainability and consistency of applications
Resources
 Download Enterprise Library and related
resources from:
• http://msdn.microsoft.com/practices
 Join the Enterprise Library Community at:
• http://codeplex.com/entlib
 Share community extensions at:
• http://codeplex.com/entlibcontrib
 Read blogs from the Enterprise Library team at:
• http://msdn.microsoft.com/practices/Comm/EntLibBlogs