Application Blocks and the Enterprise Library Part 1

Aug 8, 11:00 pm

Article Author: Dhiwakar Kusuma
.NET 3.5 Books

Introduction


I remember reading Merrick Furst’s quote "The biggest difference between time and space is that you can’t reuse time" . Interestingly, everyone in the industry is trying to prove him wrong. Why can’t one reuse time? We surely can stop reinventing, and share the knowledge one has gained thus reusing the time. Yes, this article is about reusability, reusing the time invested by someone else. At the current pace at which the software industry is moving everyone wants to be a creator of business value. During this creation process they want to minimize the time for delivery by trying to avoid the reinventing the wheel syndrome.


Everyone promotes reusability; I still maintain a text file with the findings that could prove useful for me or people surrounding me in the future. Reusability must have started at a personal level, then it moved on to promoting reusability within team, across teams and finally almost every company is having some repository for maintaining these assets.


Application blocks are Microsoft’s initiative for promoting reusability of standards and best practices for technology, in this case .NET. The Patterns and Practices group at Microsoft has been entrusted with the responsibility of spreading the best practices and Application blocks are one of their initiatives. The group had initially released application blocks that were independent in nature, data access application block, configuration management application blocks etc. Application blocks in general are given as and the developers are free to make changes and use them in their product / application without licensing issues.


Following are the application blocks that are available in the Enterprise Library:


  • Data Access

  • Exception Handling

  • Logging and Instrumentation

  • Security

  • Cryptography

  • Caching

  • Configuration

This is a two part series wherein I’ll be discussing each of the application blocks at a high level with the aim of giving you a broad overview of what is available. This first article gives an overview of the enterprise library and then proceeds to cover three of the seven application blocks namely configuration, data access, and exception handling. Part 2 will cover the remaining.


System Requirements


The current version of Enterprise Library is fully supported in Visual Studio .NET 2003. A Whidbey version is to be released shortly. Following are the system requirements for trying out the sample code available for download:


  • Visual Studio.NET 2003

  • .NET Framework version 1.1

  • Enterprise Library

  • SQL Server 7.0 or above (Optional requirement in blocks were persistent DB store could be used)

  • NUnit 2.2

Installing and Compiling the Sample Code


The code sample, available for download contains one folder for each application block sample. After extracting, you can open the solution file that is present in each of the folder and build it. It is suggested that you read the article and explore the code in parallel as you might get stuck in configuring the application.


Application Blocks Overview


Common Features


With the release of the enterprise library, all the application blocks have been brought under one box. The Enterprise Library application blocks have been designed with the following points, which also serve as its key features:


  • Extensibility : The enterprise library download contains the entire source code (highly maintainable, and based on design patterns), so users can customize the blocks and extend their functionality to suit an organization’s need.

  • Consistency : Design patterns such as factory, singleton and facade are applied in similar fashion in all the blocks. The abstract factory pattern is applied in each of the blocks and the faade pattern is applied over the abstract factory in the logging, cryptography and exception handling blocks. The configuration block is used in all the other blocks for a consistent approach in saving the configuration settings and reusability.

  • Ease of use : Simple installation procedures, a configuration GUI and extensive documentation are provided.

  • Integration : As you will see in this article the application blocks can be used as pluggable components so that they work together with other enterprise library application blocks. For example the cryptography block is being used by security application block, and the data access block is pluggable with the logging, caching and security application blocks.

  • Testablility – The TDD (Test Driven Development) approach that has been used for creating the application blocks has been shared with the users. The unit test code is available as part of the enterprise library source code. In each of the projects you can see the unit tests under the Tests folder.

  • Instrumentation – Enterprise Library uses Event logs, Performance counters, and WMI events for this purpose.

Apart from the points mentioned above, the Enterprise Library comes along with guidelines for creating your own application blocks. A sample application block, with full source code and inline comments, with the name Hello World Application Block comes along for your preview. The documentation describes the elements of an application block, guidelines for creation, and suggested topics for covering in documenting your application block.


Note: In the class diagrams that will be shown below, the parameter list and some of the methods in the classes are skipped on purpose to provide high level view of the interactions and relationship between the classes.


The Configuration Block


The ability to read and write to configuration files has been an important feature that has been requested for quite some time. There has been quite some debate as to why this feature is not part of the .NET framework ( System.Configuration ). Refer to the MSDN article titled "Remembering User Information" (Link provided in the related links section) that discusses the pros and cons of storing config data in app / web config files.


But I guess the need overcame all these debates and hence the introduction of the configuration application block. If you are wondering why I’ve started off with configuration block, read on – you will be amazed to see the features that got incorporated in to this one. The configuration block is an integral unit of all the other blocks that are part of the enterprise library and contains all the features that one would require in managing configurations. The features list provided below will help in understanding why one would go ahead with using this block compared to storing information directly in the web.config / app.config files.


Features


  • Ease of use with other enterprise library application blocks

  • Enterprise library configuration GUI replaces editing the configuration using notepad

  • Provision for reading and writing configuration information at runtime

  • Provision for storing sensitive information like passwords, connection strings etc

  • Supports storing complex serializable object graphs in the configuration file

  • Extensible storage providers and transformers

  • Provision for configuring storage provider and transformer for each configuration section

  • Multiple storage locations. You can split your application configurations into multiple sections and can store the same in multiple files whose path can be specified in the configuration file

  • Facility for caching the configuration

  • Facility for ignoring / accepting the automatic configuration change notifications

  • Provision for extending the configuration console.

Design


Client applications interact with the ConfigurationManager class to use the static functionalities of Get and Write configuration values from the configuration file. ConfigurationManager is a wrapper or a faade covering the ConfigurationBuilder which has the true implementation of functionalities related to the configuration block.


Implementations of iStorageProvderReader and iStorageProviderWriter are used for reading and writing configuration data and an implementation of iTransformer helps in formatting the content. Together all three interfaces serve as the extension points. Out of the box you get implementations for all these interfaces for handling XML. You get XmlSerializerTransformer that implements iTransformer and XmlFileStorageProvider that has the implementation of iStorageProviderWriter .



Figure 1. Class diagram for the configuration block


I briefly mentioned the configuration change notification in the features section, if you want to enable this feature attach a handler for the configuration changed event use the following code:



ConfigurationManager.ConfigurationChanged 
   += new ConfigurationChangedEventHandler(ConfigurationChanged);


Note 1: The notification system is enabled unless modified in code, you can see this in the Configuration ProjectConfigurationBuilder.csLoadMetaConfiguration() .


Note 2: The notification system is not built upon the FileSystemWatcher . Notifications are based upon the polling mechanism and the interval of the polling cannot be configured, it has to be modified in the code itself ( defaultPollDelayInMilliseconds ) in the StorageConfigurationChangeFileWatcher.cs file. For further information, take a look at "Reading configuration Information" in the enterprise library documentation.


Building the Sample Code


The following steps and code demonstrate how we can go about using the configuration block by storing a user name and password in a secured manner and later update the same using a UI. Here are the high level steps of what we need to do:


  • Creating a VS.NET solution with application configuration file

  • Using the configuration UI, provided by enterprise library, create some key / value pairs which could be later read and used in an application. In this example we are storing the connection string in the configuration file.

  • Code the solution for reading and writing the user name / password from / to the configuration file.

Below are the detailed instructions or creating this sample:


Start by creating a VS.NET solution and a Win forms project. Add an app.config file to it. In the Visual Studio solution, go to the project properties, in the Common PropertiesBuild Events – set the following value copy "$(ProjectDir)*.config" "$(TargetDir)" in Post-build event command line. This is required for the Enterprise Library configuration files to get copied to the bin directory on each build.


Open the Enterprise Library Configuration through the Enterprise Library programs menu. Choose the app.config that you added earlier through FileOpen menu. Right click the application node that appears and from the context menu choose NewConfiguration Application Block .


Right click Configuration Application Block node and from the context menu choose New Configuration Section . Change the value of the Name property from Configuration section to Identity and change the value of Encrypt to True . Right click the Identity node and from the context menu choose NewXML File Storage Provider . This provider helps in writing the information to the config file you set using the FileName property. Use Identity.config as name of the file to store the Identity section’s configuration information through the FileName property. Right click the Identity node and from the context menu choose NewXML Serializer Transformer . This will help in serializing the configuration value, which we pass as an object as you will see in the code. Note in the earlier steps that we have kept the Encrypt value as True.


Now, we have to configure the block to choose the appropriate encryption technique. We will choose to use the algorithms that come along with the Enterprise Library. There is provision for using custom encryption algorithms if there is a need. Start by right clicking on the Encryption Settings node and select NewFile Key Algorithm Storage Provider . This will kick start a wizard dialog for you. Since we do not have an existing key we will choose to Create a new Key Algorithm pair . In a multi project scenario, you can reuse an existing key pair. Click the Next button. Upon clicking the Select Algorithm button, a Type Selector dialog will popup with the list of algorithms. Select one and click on the OK button.


In the next form that shows up click on the Generate button to generate the key for you. The key will get displayed in the Key text area. Click on the Next button to proceed. Select a file for storing your key pair by clicking on the Select button and browsing for the file. Since we don’t have an existing file we shall browse to our application folder and type the file name in the select file dialog box and click on the Save button. You can opt for DPAPI (Data Protection API) for securing the information. This API helps in securing the information so that the information is available for the User account / computer only depending on whether you have chosen the User / Machine option. For example if the you chose to use Machine , and then the information will be available for decryption only on the same machine where the encryption happened. A key file that is transferred to a different machine will be of no use. Click on the Finish button to complete the encryption settings .Choose FileSave All in the Configuration GUI and return to the VS.NET


Add a reference to Microsoft.Practices.EnterpriseLibrary.Configuration.dll . Design a form that looks similar to the one shown in Figure 2below. It will have provision for entering the User Name and Password, storing these values to the configuration file and retrieving the values from the configuration file.



Figure 2. Configuration manager form


Add the following in the using section of the form’s code:



using Config = Microsoft.Practices.EnterpriseLibrary.Configuration; 


The configuration block takes all the configuration information to be saved in the form of an object. So, we will create a class IdentityInfo that will help in maintaining the user name and password information. An instance of this class will be created and populated with the information entered by the user and will be used for saving in the configuration file. Following code displays the IdentityInfo class and the code for Save_Click() and Retrieve_Click() event handlers.



public class IdentityInfo
{ public IdentityInfo(){} private string _UserName = string.Empty; private string _Password = string.Empty; public string UserName { get { return _UserName; } set { _UserName = value; } } public string Password { get { return _Password; } set { _Password = value; } }
}
private void Save_Click(object sender, System.EventArgs e)
{ IdentityInfo identity = new IdentityInfo(); identity.UserName = UserName.Text; identity.Password = Password.Text; Config.ConfigurationManager.WriteConfiguration ("UserName",identity);
}
private void Retrieve_Click(object sender, System.EventArgs e)
{ IdentityInfo identity; identity = (IdentityInfo) Config.ConfigurationManager.GetConfiguration ("Identity"); UserName.Text = identity.UserName; Password.Text = identity.Password;
}


Build and run the application, note that you will have to click on the Save button first and then go ahead with the Retrieve button. This is due to the non-existence of the configuration information the first time it is run.


The Save buttons click event handler code writes the value to the configuration file using the WriteConfiguration() function available in ConfigurationManager class. Similarly GetConfiguration() is used for retrieving the value, for the key passed as a parameter, from the configuration file through the ConfigurationManager class. Also in debug mode, you will not be able to retrieve the information that you have saved during the last build. This is due to the post build script that we had written earlier which will copy the Identity.config each time the project is built, thus overwriting the information that it has.


The Data Access Block


The data access application block is one of the widely accepted and used of the available application blocks. Also called the DAB , it is the first block that got shipped by the Patterns and Practices group. DAB has helped in saving huge chunks of code that goes inside any application that talks to a database, by providing standard production ready code based on proven industry patterns and practices.


The previous version of this block had all methods that were static making it not safe for multi-threading scenarios. In the new version, they have implemented the abstract factory pattern and have closely tied up with the configuration block for accepting the connection strings. (Note: In the previous DAB version, the connection string was expected from the caller of the code). Since, the connection string configuration is through the configuration block, one can use the encryption feature described before for securing the connection string.


Features


  • Supports multiple database systems – SQL Server, and Oracle. This can be done by selecting appropriate database types while configuring the database application block through the enterprise library configuration UI (Step by step details provided in the sample code section for this block).

  • Extensible and hence can be extended to include other database systems. For example if you want to provide support a database system other than the ones mentioned above you can do that by deriving your custom class from Database .

  • Configuration block is tightly coupled by default to retrieve the connection information. For instance when the DatabaseFactory.CreateDatabase(<database instance>) is used, the <database instance> value is used as the key to retrieve the connection information from the configuration file.

  • The configuration manager allows additional parameters to be added under the connection string node. At runtime all parameters and its corresponding values present under the connection string node, are concatenated to form the final connection string. For example you can add Min and MaxPool size parameters to define the connection pool size.

  • You can use the encryption feature of configuration application block to secure the database configuration. Note that by default the encryption is not enabled and Windows authentication is enabled as per the best practices.

  • Wherever possible, connection management is automatically done for you. This is as per "Acquire Late, Release Early" best practice for resource management.

For example when using ExecuteScalar() or ExecuteNonQuery() the connection is opened before execution and closed once the execution is complete thus implementing the best practice above with us writing very minimal code.


One should remember that since we could use the same connection string again, connection pooling is brought into action automatically and hence this frequent opening and closing of connections doesn’t affect the application’s performance. Note that connection pooling is active by default for Sql server and Oracle databases. So this works perfectly unless you alter the connection string parameters to avoid connection pooling.


  • Stored Procedure parameters are dynamically retrieved and cached during execution thus saving round trips to the DB server.

  • Acts as a pluggable component for caching, security and logging application blocks when persistent data store is required.

  • Just like the previous version of DAAB (Data Access Application Block) the enterprise library supports dynamic SQL, stored procedures and transactions. Return types include Dataset, Data Reader and Scalar values.

Design


The client application uses the DatabaseFactory for creating an instance of the Database class through DatabaseProviderFactory . Internally DatabaseProviderFactory calls its base class method ConfigurationFactory.CreateInstance().


The implementation of CreateInstance() is worth seeing, it uses reflection in .NET along with the type information retrieved from the configuration file and then calls the type’s constructor to create the instance requested. The configuration factory class is part of the configuration block that is being used by all of the application blocks.


The Database instance retrieved via the DatabaseProviderFactory is of type Microsoft.Practices.EnterpriseLibrary.Data.Sql.SqlDatabase . The implementation can be found in SqlDatabase.cs which interestingly is under Sql physical folder in Data project.



Figure 3. Class diagram for the data access block


Building the Sample Code


The following steps and code demonstrate how we can retrieve data using the data access application block:


  • Creating a VS.NET solution with application configuration file

  • Using the Configuration UI for placing database connection related information

  • Code the solution for retrieving employees’ data from the sample northwind database.

The detailed steps follow:


Create a VS.NET solution and a Win forms project. Add an app.config file to it. In the Visual Studio solution, go to the project properties, in the Common PropertiesBuild Events – set the following value copy "$(ProjectDir)*.config" "$(TargetDir)" in the Post-build event command line. This is required for the Enterprise Library configuration files to get copied to the bin directory on each build.


Open the Enterprise Library Configuration through the Enterprise Library programs menu .Choose the app.config that you had added earlier through FileOpen menu. Right click the Application node that appears and from the context menu choose NewData Access Application Block .


Inside Data Access Application BlockConnection stringsSql Connection String , change the values for the Database and Server nodes so that it points to the Northwind database within your environment. Inside the Data Access Application Block →Database Instances → change the name of this node to the Northwind DB Instance.


Change the Data Access Application BlockDefaultInstanceNode value to Northwind DB Instance. By default the database type is configured to SQL Server, however you can modify this from Data Access Application BlockDatabase types . The TypeName can be chosen from the list that appears by clicking of the ellipse button. Next choose FileSave All in the Configuration GUI and return to the VS.NET. This completes our DB configuration settings. Ideally we would have encrypted these settings, but this part has been left out for the sake of simplicity. Refer to the Configuration block sample for learning how to encrypt the configuration information.


Add a reference to Microsoft.Practices.EnterpriseLibrary.Configuration.dll , Microsoft.Practices.EnterpriseLibrary.Common.dll , and Microsoft.Practices.EnterpriseLibrary.Data.dll . These components will be available under Program FilesMicrosoft Enterprise Librarybin by default. Design a form that looks similar to the one shown in Figure 4 below. It will have a drop down list box for populating the list of employees and a command button.



Figure 4. Data access sample form


Add the following in the using section of the form’s code:



using Microsoft.Practices.EnterpriseLibrary.Data; 


In the button’s click event add the following code:



private void PopulateEmployees_Click(object sender, System.EventArgs e)
{ StringBuilder employeeFullName; Database northwindDB = DatabaseFactory.CreateDatabase("Northwind DB Instance"); String selectSQL = "SELECT FirstName, LastName FROM EMPLOYEES"; EmployeesList.Items.Clear(); using (IDataReader dr = northwindDB.ExecuteReader(System.Data.CommandType.Text,selectSQL)) { while (dr.Read()) { employeeFullName = new StringBuilder(); employeeFullName.Append(dr["FirstName"]); employeeFullName.Append(" "); employeeFullName.Append(dr["LastName"]); EmployeesList.Items.Add(employeeFullName.ToString()); } }
}


Let me explain the code a bit. The DatabaseFactory is an implementation of the factory pattern, the CreateDatabase() function reads the configuration information and returns a Database object. Note that at this point in time the database connection is not open, in fact none of the database related operations are performed. The string that we have passed as a parameter for the CreateDatabase() function identifies the section in the configuration file that is supposed to be used for retrieving the connection related information. You can store multiple connection related information in the configuration file. You just have to right click the Database Instance node in the configuration GUI and in the context menu that appears click on New Database Instance . The ExecuteReader() function returns a DataReader for us. As one may know the DataReader keeps the connection alive until the DataReader is closed. That is the reason the using clause in our code, which makes sure that the reader object is disposed.


The Exception Handling Block


As the name suggests, this block is meant for handling exceptions. The previous version of this block was released under the name exception management application block.


When compared to the previous versions, the exception handling block doesn’t own the task of actually logging the exception anymore. It delegates this task to the logging and instrumentation application block. In fact, this should be considered as one of the examples of how effective and maintainable the code becomes when the blocks work together.


One of the main features in the new version is the fact that it actually manages the exceptions with the help of policies, created by the developer, instead of simply logging the exceptions. This could make a significant difference for enterprise application design. Standards can be built around how an exception is to be treated at various layers within an application. Refer to the links areas for references on exception policies and how to create them.


Policies are basically instructions provided to the block on how to handle an exception. Inherently available policies include wrapping the exception under another exception, replacing the exception with a different one, and logging the exception.


Features


  • Exception Policies. This is a great feature that gave a new meaning for the block’s existence, which I’m sure everyone is going to like. When implemented this will bring best practices automatically into applications you develop. Through exception policies you can categorize the exceptions and inform the block as to how to handle them. For example you can define policies by which the data store specific exceptions like SQLException are to be trapped, wrapped under a custom exception and then thrown back. Some of the actions like logging, wrapping one exception under another ( WrapHandler ), and replacing one exception with another ( ReplaceHandler ) are available out of the box. Of course, there is provision for customizing the action yourself by creating a class that inherits the abstract class ExceptionHandler .

  • Using the exception block is as easy as calling the static function HandleException() in ExceptionPolicy with an exception object as parameter. If the policy is defined to handle this type of exception, the exception block will handle it accordingly.

Design


Handling exceptions is about defining policies. One defines policies using the configuration GUI (refer to the sample code) thus making the policies modifiable at any point of time. After defining policies one just has to call the HandleException() static method available in the ExceptionPolicy class, assuming that your code in unaware of how to tackle that exception. This function call will be inside your exception handling code / catch block.


The HandleException() method identifies the policy through the CreateExceptionPolicy() within the ExceptionPolicyFactory class. Once the right exception policy is retrieved the Initialize() and HandleException() methods of that class are called, which internally calls the Initialize() and HandleException() methods of the ExceptionHandler class that has been assigned to handling this exception as per the policies.


Here we have two main extension points – Creating your own Exception Handlers by deriving your class from ExceptionHandler and creating your own Exception Formatters by deriving from ExceptionFormatter (Not shown in the diagram)



Figure 5. Class Diagram for the exception block


Building the Sample Code


The following code will demonstrate how the exception handling block can be incorporated in your own application.


Create a VS.NET solution and a project. Add an app.config file to it. Go to the project properties, in the Common PropertiesBuild Events – set the following value copy "$(ProjectDir)*.config" "$(TargetDir)" in Post-build event command line. This is required for the Enterprise Library configuration files to get copied to the bin directory on each build. Open the Enterprise Library Configuration through the Enterprise Library programs menu. Choose the app.config that you had added earlier through FileOpen menu. Right click the Application node that appears and from the context menu choose NewException Handling Application Block . This action will add nodes related to the configuration application block.


In the VS.NET solution create a new class file with the following custom exception handler code. As you can see the code just returns the same exception that it had received. You can modify the HandleException() to handle the exception in your own way.



namespace ExceptionHandling
{
public class MyExceptionHandler : ExceptionHandler
{ public MyExceptionHandler(){} public override void Initialize(ConfigurationView configurationView) { //No Initialization required for MyExceptionHandler } public override Exception HandleException(Exception exception, string policyName, Guid handlingInstanceID) { //Don’t do anything handler :) return exception; } }
}


Add reference to Microsoft.Practices.EnterpriseLibrary.Configuration.dll , Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.dll . These components will be available under Program FilesMicrosoft Enterprise Librarybin by default. Compile the solution once and return back to the configuration GUI.


Go to the Exception node present under Exception Handling Application BlockException Policy and change the PostHandling action to either NotifyRethrow / None / ThrowNewException . As the name implies the PostHandling action is performed after the exception is handled as per the policies that we are defining. We will be seeing the effect of these PostHandling actions by the end of this sample.


Let us define the handler for our exception policy. Handler is nothing but the type that will be actually handling the exceptions that are passed by our application to the exception block. You can create different handlers for different exceptions. For example you can create a handler for IOException and another for ArgumentException . For this example we will create a handler for System.Exception . Right click the Exception node and in the context menu that appears click NewCustom Handler . Click on the elipse button that is present in the TypeName attribute and select one of the Exception Handlers . In our case, click on the Load An Assembly button and browse for the assembly which has the above mentioned custom exception handler.


Next choose File Save All within the Configuration GUI and return to the VS.NET. This completes our Exception Handling configuration settings.


In the Default Windows form place a single command button and in the button’s click event, place the following code.



try
{ try { throw new ApplicationException("My Exception"); } catch (System.Exception ex) { if (ExceptionPolicy.HandleException(ex,"Exception Policy")) { throw; } MessageBox.Show ("Exception not handled by Block" + ex.Message); }
}
catch (System.Exception ex)
{ MessageBox.Show("Exception Notified / Rethrown" + ex.Message);
}


Run and execute the program and click on the button. Since the exception handler is a DoNothing exception handler, the result will depend on the PostHandlingAction that you have chosen. If you have chosen None the custom exception handler code will be executed and your code will be notified not to handle it further. The NotifyRethrow custom exception handler code will be executed and your code will be notified for a re-throw by returning True for the HandleException() that you have called. In our case, if the return value is True, then we are re-throw the exception that the outer try-catch block is capturing. Finally choosing ThrowNewException will result in a new exception, which will be trapped by our outer try-catch block.


Conclusion


This first part of the two part series started off by exploring what an application block is and how they are beneficial to the development community. Next I went into some detail on three of the seven application blocks that are available. In the second part of this article I will go through the remaining four application blocks. Since the code for Enterprise Library and the above explained samples are available for download, I would encourage you to explore the same further, extend it and share your thoughts with the community.

Founders at Work

Commenting is closed for this article.