1

Enterprise Library Walkthrough

Posted in .Net, C# at November 7th, 2008 by Ben / 1 Comment »

What is Enterprise Library?

Ent.Lib 4.1 – http://msdn.microsoft.com/en-us/library/dd203099.aspx

The Microsoft Enterprise Library is a collection of reusable software components (application blocks) designed to assist software developers with common enterprise development cross-cutting concerns (such as logging, validation, data access, exception handling, and many others).

The application blocks aim to encapsulate proven best-practice for enterprise .net development.

In total there are over 9 application blocks:

  • Caching
  • Cryptography
  • Data Access
  • Exception Handling
  • Logging
  • Policy Injection
  • Security
  • Unity – Dependency Injection (IoC) container
  • Validation

This article will address the Exception, Logging, Validation and Unity application block. The new Unity Application block encapsulates the Policy Injection block and as such will not be addressed in this article along with the Caching, Cryptography and Security blocks.

Download Ent. Library 4.1 here:
http://www.microsoft.com/downloads/details.aspx?FamilyId=1643758B-2986-47F7-B529-3E41584B6CE5&displaylang=en

Important:

This article is just a rehash of information easily found in the Ent.Library documentation and online websites. To get a comprehensive understanding of how the blocks work download the Sample Code I’ve created here.

Alternately, for further demonstrations on how these blocks work, load up the included QuickStart tutorials included with the Ent. Lib download.

Note:
The solution is works with VS 2008 Team System. It utilizes the seperate Unity Application block but works with Ent. Library 3.1 for all other App. Blocks due to 3rd party software we use that has a dependency on Ent. Lib 3.1.

To migrate to Ent. Lib 4.1 just change all references for 3.1 app blocks to 4.1 app blocks.
You will also be able to remove out the the ApplicationCode/CallHandlers/*.cs files and use the 4.1 PolicyInjection CallHandlers.

NOTE: Be sure to read the rest of this article by clicking the link below.

Exception Block

http://msdn.microsoft.com/en-us/library/dd203116.aspx

The Enterprise Library Exception Handling Application Block helps developers and policy makers to create a consistent strategy for processing exceptions that occur in all architectural layers of an enterprise application. It does this in the following ways:

  • It supports exception handling in all architectural layers of an application and is not limited to service interface boundaries.
  • It allows exception handling policies to be defined and maintained at the administrative level so that policy makers, who might be system administrators as well as developers, can define how to handle exceptions. They can maintain and modify the rules that govern exception handling without changing the application block code.
  • It provides commonly used exception handling functions, such as the ability to log exception information, the ability to hide sensitive information by replacing the original exception with another exception, and the ability to maintain contextual information for an exception by wrapping the original exception inside another exception. These functions are encapsulated in .NET classes named exception handlers.
  • It can combine exception handlers to produce the desired response to an exception, such as logging exception information followed by replacing the original exception with another.
  • It lets developers create their own exception handlers.

Example:

First you define a policy. A policy describes how a specific exception type should be handled. You may decide to log the exception, or send an email out, or replace any sensitive information with a user-friendly exception.

You define the exception handling behaviour by defining zero or more handlers. System provided handlers include logging, replace exception, and wrap exception.

You then define what to do with the exception once the handlers have processed it – a post handling action. There are three post-handling actions:

  • None - Don’t do post handling.
  • ThrowNewException - Automatically throws a new exception (i.e. throw e; syntax)
  • NotifyRethrow - Notify the caller that you should re-throw the exception up the chain (i.e. use the throw; command syntax)

Once you define your exception handling policies, all you have to do is wrap code that may throw an exception with a try/catch block and let the ExceptionHandler determine how to process thrown exceptions.

In this example we’ll create a policy named “Default” that logs the exception and then notifies the caller to re-throw it.



<exceptionHandling>
  <exceptionPolicies>
    <add name="Default">
      <exceptionTypes>
        <add type="System.Exception, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" postHandlingAction="NotifyRethrow" name="Exception">
          <exceptionHandlers>
            <add logCategory="Error" eventId="100" severity="Error" title="Enterprise Library Exception Handling"
                 formatterType="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.TextExceptionFormatter,
                                Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=3.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
                 priority="0"
           type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging.LoggingExceptionHandler,
                 Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging, Version=3.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
                name="Logging Handler" />
          </exceptionHandlers>
        </add>
      </exceptionTypes>
    </add>
  </exceptionPolicies>
</exceptionHandling>

...

try
{
  throw new Exception("Message");
}
catch (Exception ex)
{
  bool rethrow = ExceptionPolicy.HandleException(ex, "Default");
  if (rethrow) { throw; }
}

Logging Block

http://msdn.microsoft.com/en-us/library/dd139916.aspx

The Enterprise Library Logging Application Block simplifies the implementation of common logging functions. Developers can use the Logging Block to write information to a variety of locations:

  • The event log
  • An e-mail message
  • A database
  • A message queue
  • A text file
  • A Windows Management Instrumentation (WMI) event
  • Custom locations using application block extension points

The application block provides a consistent interface for logging information to any destination. Your application code does not specify the destination for the information. Configuration settings determine whether the application block writes the logging information and the location for that information. This means that operators as well as developers can modify logging behavior without changing application code.

Example:

In its most simplest form the application developer just calls the Logging Facade class’s Write method to write a log message.


Logger.Write(
  new LogEntry("Test Message", "Error", 1, 1, TraceEventType.Error, "Error Level Trace", null));

The Logger class determines where and to write the message based on user-defined configuration.

There are 4 main logging concepts to be aware of:

  • Listeners - A listener is the logging sink where log messages will be directed. Eg. FlatFileListener, EventLogListener, EmailListener etc..
  • Categories - A category defines a log type and specifies which log listener to send messages of this type to.
  • Switches - Switches determine the level of log severity to pass on. I.e. if you send a log that is for information
    purposes only and the category switch value is set at Error then that message will not be logged.
  • Filters - Filters provide an extensible mechanism to filter out message logging. You may decide to exclude all logs for a particular category, etc.

Using the Exception Handling App. Block with the Logging App. Block provides enables some powerful functionality.

Validation Block

http://msdn.microsoft.com/en-us/library/cc309509.aspx

Any application that accepts input either from users or from other systems must ensure that the information is valid in terms of some set of rules that you specify. For example, when processing an order, you may need to check that a customer’s phone number has the correct number of digits, or that a date falls within a particular range. In addition, if the validation fails, you may need to send an error message that explains what is wrong.

The Enterprise Library Validation Application Block provides a library of classes, called validators, that supplies the code for validating .NET Framework data types. For example, one validator checks for null strings and another validator checks that a number falls within a specified range.

There are also special validators named AndCompositeValidator and OrCompositeValidator. If you create an AndCompositeValidator, which aggregates other validators, all validators in the composite must be true for a successful validation. If you create an OrCompositeValidator, at least one of the validators in the composite must be true for a successful validation.

You can also group validators together in a rule set. A rule set allows you to validate a complex object or graph by composing different validators of different types and applying them to elements in the object graph. Examples of these elements include fields, properties, and nested objects.

There are three ways to perform validation within the application block, and to create rule sets. They are:

  • Using configuration
  • Using attributes
  • Using code

In addition, the Validation Application Block includes adapters that allow you to use the application block with the following technologies:

  • ASP.NET
  • Windows Forms
  • Windows Communications Framework (WCF)

Example:

The simplest example demonstrates how to provide validators using c# attributes. However validators can be attached via configuration file settings.


public class Address
{
  public string Line1 { get; set; }
  public string Line2 { get; set; }

  [RangeValidator(2000, RangeBoundaryType.Inclusive, 9000, RangeBoundaryType.Exclusive)]
  public int PostCode { get; set; }

  [RegexValidator(@"QLD|NSW|VIC|NT|ACT|SA|WA|TAS")]
  public string State { get; set; }
}

Now validate the Address.


ValidationResults results = Validation.ValidateFromAttributes(new Address());
Assert.IsNotNull(results.Where(x => x.Validator.GetType() == typeof (RangeValidator) && x.Key == "PostCode").FirstOrDefault());
Assert.IsNotNull(results.Where(x => x.Validator.GetType() == typeof (RegexValidator) && x.Key == "State").FirstOrDefault());

Unity Block

http://msdn.microsoft.com/en-us/library/dd140117.aspx

The Unity Application Block (Unity) is a lightweight, extensible dependency injection container that supports constructor injection, property injection, and method call injection. You can use it with Enterprise Library to generate both Enterprise Library objects and your own custom business objects.

The Unity Application Block as a stand-alone dependency injection mechanism that does not require Enterprise Library to be installed.

The Unity container is extensible and comes with a AOP like Interception extension which provides functionality similar to the Policy Injection Application Block.

Using the DI Container

A DI container is responsible for managing the resolution of your objects and their dependencies and can be configured in a variety of ways including xml configuration and code.

Using the Unity DI container you will find you stop creating new instances of an object in your code and rely on the container to return you an instance of the object. The container will resolve the instance based on the configuration settings you initialized it with.

E.g.

No more:


IDataAccessObject dao = new SqlServerDataAccessObject();

And lots more:


UnityContainer uc = new UnityContainer();
IDataAccessObject dao = uc.Resolve<IDataAccessObject>();

Of course you have to configure the container to know which object to return when you call the Resolve method. You can do this through web|app.config configuration, programmatically or both:

E.g. Programatically


UnityContainer uc = new UnityContainer();
uc.RegisterType<IDataAccessObject, SqlServerDataAccessObject>();
var dao = uc.Resolve<IDataAccessObject>(); // returns an instance of the SqlServierDataAccessObject
dao.Insert();

How does it work?

The DI container can be thought of as a big map that manages the lifetime and resolution of objects and their dependencies. This means that when you resolve an object, any dependencies it relies on are automatically resolved too.

E.g. This example has a dependency on the IDataAccessObject class.


public class ServiceProvider : IService {
  public ServiceProvider(IDataAccessObject dao) {
    DAO = dao;
  }

  pubic IDataAccessObject DAO { get; private set; }

  public void Insert() { DAO.Insert(); }
}

...

UnityContainer uc = new UnityContainer();
uc.Register<IService, ServiceProvider>();
uc.Register<IDataAccessObject, OracleDataAccessObject>();

// when you resolve the IService, the container knows to automatically call the constructor passing in the OracleDataAccessObject that you registered.
// This form of DI is called Constructor Injection and removes the requirement on the developer to hard code in the dependency. You can also manage DI through properties and methods.
var service = uc.Resolve<IService>();
service. Insert();

Object Lifetimes:

When you register your objects with the container you can determine the lifetime of each resolution. You can pull back a new instance each time, a singleton or even a singleton per thread.

Unit Testing Benefits:

To remove a dependency (e.g. database access code) for unit testing you can just register a mock instance of an object to be returned when the tested code resolves an instance.


// Register a specific instance to be returned when resolving the interface.
var mockDAO = MockRepository.GenerateMock<IDataAccessObject>();
uc.RegisterInstance(mockDAO); // submit a specific instance to be resolved
dao = uc.Resolve<IDataAccessObject>();

Adding Interceptors

Now that we have a basic understanding of how the DI container works, we can extend it to mimic AOP cross-cutting concerns. That is we use the DI container to return us proxy objects that will run user-specified behaviour before and/or after an original member operation (e.g. method call).

For example, this simple method:


public void Add(Customer customer)
{
  DAO.Insert(customer);
}

can be influenced at runtime using the DI container and the Interceptor extension to be:


public void Add(Customer customer)
{
  Logger.Write(new LogEntry("Pre: About to validate the customer.", "Trace", 5, 100, TraceEventType.Verbose, "Add() Pre-Message:", null));
  try
  {
    ValidationResults results = Validation.Validate(customer);
    if (!results.IsValid)
    {
      throw new ArgumentValidationException(results, "customer");
    }
    DAO.Insert(customer);
  }
  catch (ArgumentValidationException ave)
  {
    Logger.Write(new LogEntry(String.Format("Error: The customer failed validation. \n {0}", ave), "Error", 1, 200, TraceEventType.Error, "Add()", , null));
    throw;
  }
  Logger.Write(new LogEntry("Post: The customer has been inserted.", "Trace", 5, 100, TraceEventType.Verbose, String.Format("Add() Pre-Message:", null));
}

All without having to touch the original code.

To configure interception, you specify some rules that tell it which operations to intercept and then an appropriate handler that will perform the interception logic.


UnityContainer uc = new UnityContainer();
uc.RegisterType<IService, ServiceProvider>();
uc.RegisterType<IDataAccessObject, SqlDataAccessObjectProvider>(new InjectionConstructor("ConnectionString"));
ObjectFactory.RegisterType<ICallHandler, LogCallHandler>("lch",
new ContainerControlledLifetimeManager(), // singleton
new InjectionConstructor(), // default constructor
new InjectionProperty("Categories", new List<string> {"Default"}), // set the logging category
new InjectionProperty("BeforeMessage", "Pre:"), // set the logging before message
new InjectionProperty("AfterMessage", "Post:")); // set the logging after message

// Configure Interceptors (Proxy Invocations) on the IService.Add(Customer customer) method.
var configurator = ObjectFactory.AddNewExtension<Interception>().Configure<Interception>();
configurator.AddPolicy("services")
.AddMatchingRule(new NamespaceMatchingRule("ApplicationCode.Services.*"))
.AddMatchingRule(new MethodSignatureMatchingRule("Add", new[] {"Customer"}));
	.AddCallHandler("lch"); // run the logging call handler
configurator.SetInterceptorFor<IService>(new InterfaceInterceptor());

Conclusion:

This article introduces you to core concepts of the Enterprise Library Application Blocks and how they can be used to enhance your application development projects. Apart from reading, downloading and experimenting with the official Enterprise Library source code and quickstarts, I suggest downloading the included sample code and viewing the test cases to get a greater understanding of how the concepts can be utilized.

Downloads:
Sample Code

Published in .Net, C#

One Response to “Enterprise Library Walkthrough”

  1. November 23rd, 2009 at 10:50 pm #wes

    While using Microsoft Enterprise Library Caching Application Block, I came across some limitations of CAB. I am talking about the issues like Scalability and Reliability. A good read can be found here about these limitations.

Leave a Reply