Policy Injection Application Block Sample - Enterprise Library 3.0 Coolness
by David Hayden ( Microsoft MVP C# ), Filed: Enterprise Library 3.0
If you haven't downloaded the Enterprise Library 3.0 February 2007 CTP, I highly recommend downloading it. It is a pretty significant release for a few reasons:
- It is the last CTP before RTM
- All the blocks are Release Candidates except for the Policy Injection Application Block
- Includes a new Application Block - Policy Injection Application Block
The Policy Injection Application Block ( PIAB ) is new in this release and may change the way you use Enterprise Library and think about development in general.
If you look at the code in your applications, you will see a lot of non-business related code, such as logging, security, exception handling, validation, etc. This “infrastructure” code is very necessary, but can be very distracting and make the core business logic hard to read, understand, and find :) Wouldn't it be nice to somehow describe these infrastructure concerns across your application in the form of policies and attach handlers to those policies that carry out these infrastructure related tasks / concerns for you without you explicity coding them?! Heck yeah it would :)
Put simply, the Policy Injection Application Block can save you from having to write all those boring validation, security, exception handling, and security-related code and instead allow you to write policies in your configuration file associated with them. These policies can then be mapped to classes in your application based on matching rules. The matching rules can match a policy to an entire assembly, a namespace, types, methods, method signatures, etc.
This concept isn't new, but it sure is sweet to have the functionality in Enterprise Library :)
Policy Injection Application Block Sample
Tom gets the honor of the first known sample of the Policy Injection Application Block: Configuring the Policy Injection Application Block. I actually snagged some of his config settings, because the Enterprise Library Configuration Tool does not support the Policy Injection Application Block at the moment, which can make it a little difficult to work with at this stage.
My sample centers around saving a person who subscribes to my website to the database. Here is my simple Subscriber Class that will be saved to a Subscribers Table in my database:
public class Subscriber
{
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
private string _emailAddress;
public string EmailAddress
{
get { return _emailAddress; }
set { _emailAddress = value; }
}
}
I have a Data Access Object ( DAO ), called SubscriberDAO, that is responsible for saving the subscriber to the database.
public class SubscriberDAO : IDAO<Subscriber>
{
public void Save(Subscriber subscriber)
{
// Save...
}
}
The SubscriberDAO implements the following interface:
public interface IDAO<T>
{
void Save(T entity);
}
Pretty basic stuff. We create an instance of subscriber and get an instance of IDAO<Subscriber> to save it.
Subscriber subscriber = new Subscriber();
subscriber.Name = "John Doe";
subscriber.EmailAddress = "john.doe@whoami.com";
IDAO<Subscriber> dao =
DAOFactory.Create<IDAO<Subscriber>>();
dao.Save(subscriber);
The only problem is that this code is missing all the real-world infrastructure code that is needed, such as validating the subscriber. When we pass the subscriber to be saved we need to verify it is valid before saving. Below is a bit of pseudo-code that shows me using the Validation Application Block to validate the subscriber with the possibility of throwing and logging an exception if it is invalid ( Note: the validation code could also be in the Subscriber Class itself. )
public class SubscriberDAO : IDAO<Subscriber>
{
public void Save(Subscriber subscriber)
{
// Is subscriber valid?
ValidationResults results =
Validation.Validate(subscriber);
if (!results.isValid)
throw exception?
log exception?
// Save...
}
}
As you can see, things get ugly really quickly in the real world and we now have a bunch of validation, exception handling, and logging code in our SubscriberDAO Class that has nothing to do with saving the subscriber.
Define a Policy
Rather than muck up my SubscriberDAO Class with all that validation and exception handling code, I am going to define a policy using the Policy Injection Application Block that deals with validation and exception handling. Here is a snipped version of the Policy Injection Configuration in my App.config which basically embodies validation, exception handling, and logging of the exception:
<policyInjection>
<policies>
<add name="Validation">
<matchingRules>
<add type=" ... TagAttributeMatchingRule, ..."
name="Tag Matching Rule"
match="ValidateEntity" ignoreCase="true" />
</matchingRules>
<handlers>
<add name="Exception Handler"
type="..." exceptionPolicyName="LoggingPolicy" />
<add name="Validation Handler"
type="..." specificationSource="Both" />
</handlers>
</add>
</policies>
</policyInjection>
The Validation Policy is applied based on the Tag Matching Rule. Wherever I decorate my class with [Tag(“ValidateEntity“)], the ValidationPolicy will call the Exception Handler and the Validation Handler. It is a bit more complicated than that, but that will suffice for now :)
So, I have the perfect place to add the tag that represents this policy:
public interface IDAO<T>
{
[Tag("ValidateEntity")]
void Save(T entity);
}
Let's put it right on my interface so it will apply to all the Save Methods for all my DAO's! Now everytime the Save Method gets called on a DAO my Exception and Validation Handlers will be invoked prior to the calling of the Save Method. The Policy Injection Application Block will intercept that call to Save beforehand and call the handlers first :) If the subscriber is invalid, the Save Method will actually never get called.
There is a catch, however. The Policy Injection Application Block needs to create our SubscriberDAO so it can sneak you a proxy class that looks, smells, and acts like the real SubscriberDAO.
Hence our calling code now looks like:
Subscriber subscriber = new Subscriber();
subscriber.Name = "John Doe";
subscriber.EmailAddress = "john.doe@whoami.com";
IDAO<Subscriber> dao =
PolicyInjection.Create<SubscriberDAO,
IDAO<Subscriber>>();
dao.Save(subscriber);
I would prefer to see this directly:
IDAO<Subscriber> dao =
PolicyInjection.Create<IDAO<Subscriber>>();
but that's another story :)
So What's All The Excitement About?!
The exciting part is what happens that I really can't do justice from a blog post :) If I write the following code that represents an invalid subscriber as based on Validation Application Block settings I have in my App.config file:
// Invalid - no name or email address
Subscriber subscriber = new Subscriber();
try
{
IDAO<Subscriber> dao = PolicyInjection.Create
<SubscriberDAO, IDAO<Subscriber>>();
dao.Save(subscriber);
}
catch(ArgumentValidationException ex)
{
ValidationResults results =
ex.ValidationResults;
}
The Save Method on the SubscriberDAO is never called, because the proxy class intercepts the call to Save and runs the Validation Handler and discovers the subscriber is invalid. This causes an ArgumentValidationException to be thrown which is caught by my Exception Handler, logged, and rethrown so I can get the broken rules ( ValidationResults ) in the client code and do something with it.
The validation, exception handling, and logging would be a decent amount of code mucking up our Save Method, but we were able to wrap it up via a simple tag on our Interface:
public interface IDAO<T>
{
[Tag("ValidateEntity")]
void Save(T entity);
}
If that isn't mind blowing enough, we don't need that tag! We could use another Matching Rule that didn't require a tag :)
Conclusion
Freaking cool!
Source: David Hayden ( Microsoft MVP C# )
Filed: Enterprise Library 3.0