You are on page 1of 147

Enterprise Library for .NET Framework 2.

0 Hands On Labs

Enterprise Library Hands On Labs


Lab 1: Data Access Block
After completing this lab, you will be able to:

• Query a database using encrypted configuration settings.


• Use the data access block to read and update a database.

Scenario
This lab demonstrates the use of the Enterprise Library Data Access
Application Block. It requires a (local)\SQLEXPRESS instance of SQL Server
or SQL Server Express.

Estimated Time To Complete this lab: 30 minutes.

Exercise 1: Dynamic SQL with the Data Access


Application Block
This exercise demonstrates how to do basic database access, using the Data
Access Block from the Enterprise Library. It will also show how to configure
the block, providing runtime database selection, accessed via an alias in the
code.

First step

1. Open the SimpleData.sln file.

Create the QuickStarts Database

1. As part of the installation of Enterprise Library, there is a batch file to


set up the Quick Starts database. Unfortunately, the deployed .sql file
is in ANSI, while OSQL uses the OEM code page. When you run the
script, you may find that the data entered into the database has its
accents distorted. To fix this problem, re-save the file as UTF16, and
then re-run the batch file.
2. Open the file DataAccessQuickStarts.sql in Notepad, which can be
found in the [Enterprise Install Dir]\QuickStarts\Data directory. Choose
File | Save As. Select Unicode as the encoding. Should the Read

Document made for self preparation (Abhishek Maitrey) 1


Enterprise Library for .NET Framework 2.0 Hands On Labs

only attribute warning appear, then select the file in Window Explorer.
Choose File | Properties and uncheck the Read only checkbox at the
bottom of the window.

3. Click Save, and click Yes to overwrite the file.


4. Run the batch file SetUpQuickStartsDB.bat, from the same
directory.

Note: the database will be installed into the (local)\SQLEXPRESS


instance.

Review the Application

1. Select the MainForm.cs file in the Solution Explorer. Select the View
| Designer menu command.

Document made for self preparation (Abhishek Maitrey) 2


Enterprise Library for .NET Framework 2.0 Hands On Labs

This application contains a DataGrid and some menus. You will


implement counting the available customers in the database, and then
loading the customers into the datagrid, using the data access block.

Implement the Customer Menu Items

1. Select the CustomerManagment project. Select the Project | Add


Reference … menu command. Select the Browse tab and select the
following assemblies located here:

• Microsoft.Practices.EnterpriseLibrary.Common.dll, and
• Microsoft.Practices.EnterpriseLibrary.Data.dll.

You will need to add the reference to the Common assembly,


because the Data Block is instrumented and the
IInstrumentationEventProvider is defined in the Common assembly.

2. Select the MainForm.cs file in the Solution Explorer. Select the View
| Code menu command.
3. Add the following namespace inclusion to the list of namespaces at the
top of the file:

using Microsoft.Practices.EnterpriseLibrary.Data;

4. Find the mnuCount_Click method (the Customer | Count menu


click event handler), and add the following code (inserted code in
bold):

private void mnuCount_Click(object sender, System.EventArgs e)


{
// TODO: Count Customers

Database db = null;
db = DatabaseFactory.CreateDatabase("QuickStarts
Instance");

int count = (int)db.ExecuteScalar(


CommandType.Text,
"SELECT COUNT(*) FROM Customers");

Document made for self preparation (Abhishek Maitrey) 3


Enterprise Library for .NET Framework 2.0 Hands On Labs

string message = string.Format(


"There are {0} customers in the database",
count.ToString());

MessageBox.Show(message);
}

The code above first obtains an Enterprise Library database instance


using the data access configuration for the database instance name
"QuickStarts Instance" within the configuration file. The real
database connection is not opened at this point.

The db.ExecuteScalar command has multiple overloads. The selected


overload allows specifying some literal SQL to execute, and returns the
result in a similar manner to the SqlCommand .ExecuteScalar
method.

The db.ExecuteScalar method call is responsible for opening and


closing the connection to the real database defined in the configuration
file, as well as performing any instrumentation required.

5. Find the mnuLoad_Click method (the Customer | Load menu click


event handler), and add the following code (inserted code in bold):

private void mnuLoad_Click(object sender, System.EventArgs e)


{
// TODO: Load Customers

Database db = null;
db = DatabaseFactory.CreateDatabase();

DataSet ds = db.ExecuteDataSet(
CommandType.Text,
"SELECT * From Customers");

Document made for self preparation (Abhishek Maitrey) 4


Enterprise Library for .NET Framework 2.0 Hands On Labs

dataGrid1.DataSource = ds.Tables[0];
}

The db.ExecuteDataSet method is responsible for opening and


closing the connection, as well as returning a new dataset filled with
the results of the SQL Query, which may include multiple tables.

Note: This time we have not passed a database instance name to the
CreateDatabase method. Rather the default database defined in the
application configuration file will be used.

Configure the application

1. Add a new Application configuration file (App.config) to the


CustomerManagement project. Click on the
CustomerManagement project. Select the Project| Add New
Item… menu command. Select Application configuration file
template. Leave the Name as App.config.

2. We will use the Enterprise Library Configuration tool to configure our


application. You may either start this tool from the Windows Start
menu (select All Programs | Microsoft patterns and practices |

Document made for self preparation (Abhishek Maitrey) 5


Enterprise Library for .NET Framework 2.0 Hands On Labs

Enterprise Library | Enterprise Library Configuration) and open


the App.config file located here.

Alternatively you may configure Visual Studio to open the configuration


file with the tool, as described below.

3. Select the App.config file in the Solution Explorer. Select the View |
Open With… menu command. The OpenWith dialog is displayed.
Click the Add button.

4. In the Add Program dialog, set the Program name to the


EntLibConfig.exe file found here. Set the Friendly name to
Enterprise Library Configuration. Click the OK button.

Document made for self preparation (Abhishek Maitrey) 6


Enterprise Library for .NET Framework 2.0 Hands On Labs

Visual Studio will pass the configuration file (App.config) to the


EntLibConfig.exe program as a command line parameter.

5. In the Open With dialog, select the newly entered Enterprise


Library Configuration program and click the OK button.

6. If you have a connectionStrings section defined in your


machine.config file, you will find that the Enterprise Library

Document made for self preparation (Abhishek Maitrey) 7


Enterprise Library for .NET Framework 2.0 Hands On Labs

Configuration tool automatically creates a Data Access Application


Block for you.

If so select the Data Access Application Block | Connection


Strings node and select the Action | New | Connection String
menu command.

7. Alternatively, if you do not have a Data Access Application Block


defined, right click on the Application and select New | Data Access
Application Block.

Document made for self preparation (Abhishek Maitrey) 8


Enterprise Library for .NET Framework 2.0 Hands On Labs

8. Select the Data Access Application Block | Connection Strings |


Connection String node. Change the Name property to
QuickStarts Instance.

Document made for self preparation (Abhishek Maitrey) 9


Enterprise Library for .NET Framework 2.0 Hands On Labs

This name has to match the name you used in the code. This is
how you can create an alias in code that maps to the concrete
database instance you wish to use at runtime.

9. Select the Database node for this connection string. Change the
Value property on the right hand side to EntLibQuickStarts.

Document made for self preparation (Abhishek Maitrey) 10


Enterprise Library for .NET Framework 2.0 Hands On Labs

10. Similarly, select the Server node, and set its Value to
"(local)\SQLEXPRESS".

Document made for self preparation (Abhishek Maitrey) 11


Enterprise Library for .NET Framework 2.0 Hands On Labs

11. Select the Data Access Application Block node. Set the
DefaultDatabase property is to the QuickStarts Instance.

Document made for self preparation (Abhishek Maitrey) 12


Enterprise Library for .NET Framework 2.0 Hands On Labs

12. Select the File | Save All menu command to save the application
configuration. Close the Enterprise Library Configuration tool.

Run the application

1. Select the Debug | Start Without Debugging menu command to


run the application. Click on Yes in the dialog box warning about the
app.config being modified outside the source editor.

Select the Customers | Count menu command to view the number of


customers in the database, and use the Customers | Load menu
command to fill the DataGrid.

2. Close the application and Visual Studio .NET.

To check the finished solution, open the SimpleData.sln file.

Exercise 2: Stored Procedures and Updates with the


Data Access Block
This exercise demonstrates using the data access block to wrap stored
procedure access, as well as performing updates using a strongly typed
DataSet.

First step

1. Open the DataEx2.sln file.

Add the Categories Table to the QuickStarts Database

1. Run the batch file SetUpEx02.bat, which can be found in the lab
directory:

labs\cs\Data Access\exercises\ex02\DbSetup.

This adds a set of categories that you can use to filter the set of
products you retrieve and manipulate.

Document made for self preparation (Abhishek Maitrey) 13


Enterprise Library for .NET Framework 2.0 Hands On Labs

Note: the modifications will be made to the (local)\SQLEXPRESS


instance.

Review the application

1. Select the MainForm.cs in the Solution Explorer. Select the View |


Designer menu command.

This application will allow us to select a particular category, load the


products for that category, and then save any changes you make.

Implement database retrieval

1. Select the MainForm.cs in the Solution Explorer. Select the View |


Code menu command. Add the following namespace inclusion to the
list of namespaces at the top of the file:

The required references to the Data and Common assemblies have


already been added.

using Microsoft.Practices.EnterpriseLibrary.Data;

2. Add the following private field to the form, as you'll re-use this
database instance in multiple places.

private Database _db = DatabaseFactory.CreateDatabase("QuickStarts


Instance");

Note that you can hold onto this, as the Database instance does not
represent an open connection, but instead represents a reference to a
database.

If you had a SqlConnection object instead, then you would not be


complying with the Acquire Late, Release Early model.

3. Find the MainForm_Load method, and insert the following code to


obtain the set of categories using a DataReader:

Document made for self preparation (Abhishek Maitrey) 14


Enterprise Library for .NET Framework 2.0 Hands On Labs

private void MainForm_Load(object sender, System.EventArgs e)


{
this.cmbCategory.Items.Clear();

// TODO: Use a DataReader to retrieve Categories


using (IDataReader dataReader =
_db.ExecuteReader("GetCategories"))
{
// Processing code
while (dataReader.Read())
{
Category item = new Category(
dataReader.GetInt32(0),
dataReader.GetString(1),
dataReader.GetString(2));

this.cmbCategory.Items.Add(item);
}
}

if (this.cmbCategory.Items.Count > 0)
this.cmbCategory.SelectedIndex = 0;
}

One of the overloads of the Database.ExecuteReader method takes


a string, and an optional set of parameters. This overload will locate
the stored procedure given by the string, read its meta-data (and
cache it for future use), and set parameters with the values of any
arguments provided.

Note: You are not doing any connection management here, but it is
very important to Dispose the data reader returned. This is
accomplished by the using statement in the code above. When the
data reader is disposed, the underlying DbConnection is also closed.

4. Find the cmbCategory_SelectedIndexChanged method and insert


the following code, which will read a subset of the products, based on
the selected category drop down.

Document made for self preparation (Abhishek Maitrey) 15


Enterprise Library for .NET Framework 2.0 Hands On Labs

private void cmbCategory_SelectedIndexChanged(object sender,


System.EventArgs e)
{
this.dsProducts.Clear();

Category selectedCategory =
(Category)this.cmbCategory.SelectedItem;
if (selectedCategory == null)
return;

// TODO: Retrieve Products by Category


_db.LoadDataSet(
"GetProductsByCategory",
this.dsProducts,
new string[] { "Products" },
selectedCategory.CategoryId);
}

There are two methods on the Database class that populate a DataSet;
ExecuteDataSet and LoadDataSet. ExecuteDataSet returns a
newly created DataSet, while LoadDataSet populates an existing one.

The overload used here takes a stored procedure as the first


argument, the dataset to populate, a set of tables to map the result of
the procedure into, and an arbitrary number of arguments. The
additional arguments are mapped to any stored procedure arguments
retrieved from the database metadata.

Implement updating the database

1. Find the btnSave_Click method. Insert the following code, which will
update the database based on any changes in the dataset.

private void btnSave_Click(object sender, System.EventArgs e)


{
// TODO: Use the DataSet to update the Database
System.Data.Common.DbCommand insertCommand = null;
insertCommand =
_db.GetStoredProcCommand("HOLAddProduct");
_db.AddInParameter(insertCommand, "ProductName",

Document made for self preparation (Abhishek Maitrey) 16


Enterprise Library for .NET Framework 2.0 Hands On Labs

DbType.String, "ProductName", DataRowVersion.Current);


_db.AddInParameter(insertCommand, "CategoryID",
DbType.Int32, "CategoryID", DataRowVersion.Current);
_db.AddInParameter(insertCommand, "UnitPrice",
DbType.Currency, "UnitPrice", DataRowVersion.Current);

System.Data.Common.DbCommand deleteCommand = null;


deleteCommand =
_db.GetStoredProcCommand("HOLDeleteProduct");
_db.AddInParameter(deleteCommand, "ProductID",
DbType.Int32, "ProductID", DataRowVersion.Current);
_db.AddInParameter(deleteCommand, "LastUpdate",
DbType.DateTime, "LastUpdate",
DataRowVersion.Original);

System.Data.Common.DbCommand updateCommand = null;


updateCommand =
_db.GetStoredProcCommand("HOLUpdateProduct");
_db.AddInParameter(updateCommand, "ProductID",
DbType.Int32, "ProductID", DataRowVersion.Current);
_db.AddInParameter(updateCommand, "ProductName",
DbType.String, "ProductName", DataRowVersion.Current);
_db.AddInParameter(updateCommand, "CategoryID",
DbType.Int32, "CategoryID", DataRowVersion.Current);
_db.AddInParameter(updateCommand, "UnitPrice",
DbType.Currency, "UnitPrice", DataRowVersion.Current);
_db.AddInParameter(updateCommand, "LastUpdate",
DbType.DateTime, "LastUpdate",
DataRowVersion.Current);

int rowsAffected = _db.UpdateDataSet(


this.dsProducts,
"Products",
insertCommand,
updateCommand,
deleteCommand,
UpdateBehavior.Standard);
}

Document made for self preparation (Abhishek Maitrey) 17


Enterprise Library for .NET Framework 2.0 Hands On Labs

When updating a database, it is required to manually create the


wrappers around the stored procedures, as it needs to know the
mapping between the columns in the DataTable and the stored
procedure arguments.

With this overload of the UpdateDataSet method, it is possible to get


the Data Access Block to execute all the updates transactionally, by
setting the UpdateBehaviour to Transactional. For more information,
see the Enterprise Library documentation.

Run the application

1. Select the Debug | Start Without Debugging menu command to


run the application.

Select a category from the drop down, and observe how it loads and
saves the data.

More information

1. For more information on designing and implementing data access


layers, and knowing whether to create strongly-typed data access
layers (via code generation) versus weakly typed data access layer
(e.g. the data access block) see the "Developing Microsoft® .NET
Applications Using Code Generation, UI Process and Abstraction"
course which is part of the Mastering Industrial Strength .NET series.
This uses Enterprise Library as one of the options for abstracting data
access, as well as implementing code generation to generate
transaction aware data access layers.

To check the finished solution, open the DataEx2.sln file.

Exercise 3: Encrypting Connection Information


In this exercise, you will encrypt the configuration to prevent 'connection
string discovery' by someone copying the application configuration file.

First step

1. Open the DataEx3.sln file.

Encrypt the Database Configuration

Document made for self preparation (Abhishek Maitrey) 18


Enterprise Library for .NET Framework 2.0 Hands On Labs

1. The .NET Framework version 2.0 natively supports protected


configuration via the Configuration namespace.

You can use protected configuration to encrypt sensitive information,


including user names and passwords, database connection strings, and
encryption keys, in an application configuration file. Encrypting
configuration information can improve the security of your application
by making it difficult for an attacker to gain access to the sensitive
information even if the attacker gains access to your configuration file.

Encryption and decryption is performed using a


ProtectedConfigurationProvider class. The following list describes
the protected configuration providers included in the .NET Framework:

• DPAPIProtectedConfigurationProvider. Uses the Windows


Data Protection API (DPAPI) to encrypt and decrypt data.
• RsaProtectedConfigurationProvider. Uses the RSA
encryption algorithm to encrypt and decrypt data.

Both providers offer strong encryption of data; however, if you are


planning to use the same encrypted configuration file on multiple
servers, such as a Web farm, only the
RsaProtectedConfigurationProvider enables you to export the
encryption keys used to encrypt the data and import them on another
server.

By default, RSA key containers are tightly protected by NTFS access


control lists (ACLs) on the server where they are installed. This
improves the security of the encrypted information by restricting who
can access the encryption key.

Note: Encrypted configuration information is decrypted when loaded


into the memory that is used by your application. If the memory for

Document made for self preparation (Abhishek Maitrey) 19


Enterprise Library for .NET Framework 2.0 Hands On Labs

your application is compromised, the sensitive information from your


protected configuration section might be compromised as well.

2. Select the ProductMaintenance project. Select the Project | Add


Reference … menu command. Select the .NET tab and select the
following assembly.

• System.Configuration.dll.

3. Select the Program.cs file in the Solution Explorer. Select the View |
Code menu command. Add the following namespace inclusion to the
list of namespaces at the top of the file:

using System.Configuration;

4. Add the following code to the ProtectConfiguration method.

static void ProtectConfiguration()


{
// TODO: Protect the Connection Strings
string provider = "RsaProtectedConfigurationProvider";

Document made for self preparation (Abhishek Maitrey) 20


Enterprise Library for .NET Framework 2.0 Hands On Labs

Configuration config = null;


config =
ConfigurationManager.OpenExeConfiguration(ConfigurationUse
rLevel.None);

ConfigurationSection section = config.ConnectionStrings;

if ((section.SectionInformation.IsProtected == false) &&


(section.ElementInformation.IsLocked == false))
{
// Protect (encrypt) the "connectionStrings" section.
section.SectionInformation.ProtectSection(provider);

// Save the encrypted section.


section.SectionInformation.ForceSave = true;
config.Save(ConfigurationSaveMode.Full);
}
}

Run the application

1. Select the Debug | Start Without Debugging menu command to


run the application.

Note that it behaves the same as in the previous exercise.

2. Open the ProductMaintenance.exe.config file in the project


bin\Debug directory located here. Note the connection strings are
encrypted.

To check the finished solution, open the DataEx3.sln file.

Copyright © 2005 Microsoft. All Rights Reserved.

Document made for self preparation (Abhishek Maitrey) 21


Enterprise Library for .NET Framework 2.0 Hands On Labs

Enterprise Library Hands On Labs


Lab 2: Caching Block
After completing this lab, you will be able to:

• Add persistent caching to a windows application.


• Use background loading to populate a cache.

Scenario
This lab demonstrates the use of the Enterprise Library Caching Block. It
requires a (local)\SQLEXPRESS instance of SQL Server or SQL Server
Express.

Estimated Time To Complete this lab: 30 minutes.

Exercise 1: Using the Caching Block for performance


This exercise demonstrates how to implement caching using the Caching
Block from the Enterprise Library. You will perform caching to speed up
display of employee details, and then make the cache persistent, to support
an offline scenario.

First step

1. Open the EmployeeBrowser.sln file.

Populate the QuickStarts database with employee data

1. Run the batch file SetCachingHOL.bat, which can be found in the lab
directory:

labs\cs\Caching\setup.

This adds a set of employees which you will use to create an employee
directory.

Document made for self preparation (Abhishek Maitrey) 22


Enterprise Library for .NET Framework 2.0 Hands On Labs

Note: the database will be installed into the (local)\SQLEXPRESS


instance.

Review the application

1. This application is a browser for the employee contact details stored in


the database. As part of the browser the application displays a
photograph of the employee.

Although the application loads all employee records at startup, it


doesn't load the photographs until they are requested. Images can be
large, and retrieving all images (if they are to be viewed or not) could
seriously slow the startup performance.

2. Select the MainForm.cs file in the EmployeeBrowser project.


Select the View | Code menu command and locate the
MainForm_Load method. The Form uses a class called
EmployeeService to obtain the data to display. This in turn uses the
EmployeeDataProvider class, as displayed in the picture below:

Currently, the EmployeeService just delegates directly to the


EmployeeDataProvider class. You will enhance this class to use the
Caching Block and to react appropriately when the application is
offline.

3. Select the EmployeeDataProvider.cs file in the Solution Explorer.


Select the View | Code menu command and locate the
GetEmployeePhotoData method.

Note: The GetEmployeePhotoData method adds a 1 second delay to


the call to simulate slow database access.

Document made for self preparation (Abhishek Maitrey) 23


Enterprise Library for .NET Framework 2.0 Hands On Labs

4. Select the Debug | Start Without Debugging menu command to


run the application.

Browse through the employees.

Note: There is a significant delay while browsing through photos, even


when you have viewed a photo previously.

Implement caching in the EmployeeService class

1. Select the EmployeeBrowser project. Select the Project | Add


Reference… menu command. Select the Browse tab and select the
following assembly located here:

• Microsoft.Practices.EnterpriseLibrary.Caching.dll.
2. Select the EmployeeService.cs file in the Solution Explorer. Select
the View | Code menu command.
3. Add the following namespace inclusion to the list of namespaces at the
top of the file:

using Microsoft.Practices.EnterpriseLibrary.Caching;

4. Add the following code to the GetEmployeePhoto method.

public static Bitmap GetEmployeePhoto(Guid employeeId)


{
byte[] photoData = null;

// TODO: Add Caching of Photo

// Attempt to retrieve from cache


CacheManager cache = CacheFactory.GetCacheManager();
photoData = (byte[])cache[employeeId.ToString()];

Document made for self preparation (Abhishek Maitrey) 24


Enterprise Library for .NET Framework 2.0 Hands On Labs

// Retrieve from dataProvider if not in Cache


if (photoData == null)
{
EmployeeDataProvider dataProvider = new
EmployeeDataProvider();
photoData = dataProvider.GetEmployeePhotoData(employeeId);

cache.Add(employeeId.ToString(), photoData);
}

// No data found.
if (photoData == null)
return null;

// Convert bytes to Bitmap


using (MemoryStream ms = new MemoryStream(photoData))
{
return new Bitmap(ms);
}
}

This method uses the factory model, as with the rest of Enterprise
Library, to create a new CacheManager instance. This can be purely in-
memory, or can be backed by a physical storage medium, depending
on configuration.

Items can be retrieved from the cache by using an indexer, and can be
added (or replaced) by using the Add method. The overload used in
this method does not specify an expiration policy.

5. Add the following code to the ClearCache method, to allow the form
to request the service to get new data.

public static void ClearCache()


{
// TODO: Clear Cache
CacheManager cache = CacheFactory.GetCacheManager();
cache.Flush();
}

Document made for self preparation (Abhishek Maitrey) 25


Enterprise Library for .NET Framework 2.0 Hands On Labs

This method will remove all items from the cache.

"Open With…" Configuration Console

1. We will use the Enterprise Library Configuration tool to configure our


application. You may either start this tool from the Windows Start
menu (select All Programs | Microsoft patterns and practices |
Enterprise Library | Enterprise Library Configuration) and open
the App.config file located here.

Alternatively you may configure Visual Studio to open the configuration


file with the tool, as described below.

2. Select the App.config file in the Solution Explorer. Select the View |
Open With… menu command. The OpenWith dialog is displayed.
Click the Add button.

3. In the Add Program dialog, set the Program name to the


EntLibConfig.exe file found here. Set the Friendly name to
Enterprise Library Configuration. Click the OK button.

Document made for self preparation (Abhishek Maitrey) 26


Enterprise Library for .NET Framework 2.0 Hands On Labs

Visual Studio will pass the configuration file (App.config) to the


EntLibConfig.exe program as a command line parameter.

4. In the Open With dialog, select the newly entered Enterprise


Library Configuration program and click the OK button.

Configure the application

Document made for self preparation (Abhishek Maitrey) 27


Enterprise Library for .NET Framework 2.0 Hands On Labs

1. Right click on the Application and select New | Caching Application


Block.

2. Select the node Caching Application Block | Cache Managers |


Cache Manager. Here some of the settings you can change to tune
the performance of our cache. For now, leave the settings as they are.

Document made for self preparation (Abhishek Maitrey) 28


Enterprise Library for .NET Framework 2.0 Hands On Labs

3. Save the application configuration by choosing File | Save All. Close


the Enterprise Library Configuration Console.
4. Select the App.config in the Visual Studio Solution Explorer. Select
the View | Open menu command.

The App.config file now contains the caching configuration settings you
added previously. Notice the backing store is Null Storage. That is,
the cache will be stored in-memory.

Run the application

1. Select the Debug | Start Without Debugging menu command to


run the application.

Document made for self preparation (Abhishek Maitrey) 29


Enterprise Library for .NET Framework 2.0 Hands On Labs

Browse through the employees and notice the performance difference


for cached photos.

2. Close the application and close Visual Studio .NET.

To check the finished solution, open the EmployeeBrowser.sln file.

Exercise 2: Persistent Caching


This exercise demonstrates using persistent backing stores and expiration
policies of an offline cache.

First step

1. Open the EmployeeBrowser.sln file.

Implement offline caching

1. Select the EmployeeServices.cs in the Visual Studio Solution


Explorer. Select the View | Code menu command. Add the following
using statement to the top of the file:

using Microsoft.Practices.EnterpriseLibrary.Caching.Expirations;

2. Locate the GetContactDetails method, and add the following code:

public static EmployeesDataSet GetContactDetails()


{
EmployeesDataSet dsEmployees = null;

// TODO: Add persistent caching with time-out

// Attempt to retrieve from cache


CacheManager cache = CacheFactory.GetCacheManager();
dsEmployees = (EmployeesDataSet)cache[CACHE_KEY];

// Retrieve from dataProvider if not in Cache and Online


if (dsEmployees == null && ConnectionManager.IsOnline)

Document made for self preparation (Abhishek Maitrey) 30


Enterprise Library for .NET Framework 2.0 Hands On Labs

{
EmployeeDataProvider dataProvider = new
EmployeeDataProvider();
dsEmployees = dataProvider.GetEmployees();

// Expire in 2 days
AbsoluteTime expiry = new AbsoluteTime(new
TimeSpan(2, 0, 0, 0));
cache.Add(CACHE_KEY, dsEmployees,
CacheItemPriority.High, null,
new ICacheItemExpiration[] { expiry });
}

return dsEmployees;
}

This code will only attempt to contact the database when the
application is online.

This contact details are loaded into the cache using an overload of the
Add method which allows the specifying of cache item priority, a cache
item removal callback (which must be serializable for persistent
caches), and a set of expiration policies. In this case, you do not want
to allow our users to keep the employee data on their machines for
more than 2 days without checking in. This helps to reduce the
possibility of an employee taking the contact data to another company,
as the caching infrastructure will remove the contents once they have
expired.

3. Modify the GetEmployeePhoto method to not attempt to retrieve


information from the database when offline (modified code in bold):

public static Bitmap GetEmployeePhoto(Guid employeeId)


{
byte[] photoData = null;

Document made for self preparation (Abhishek Maitrey) 31


Enterprise Library for .NET Framework 2.0 Hands On Labs

// Attempt to retrieve from cache


CacheManager cache = CacheFactory.GetCacheManager();
photoData = (byte[])cache[employeeId.ToString()];

// TODO: Retrieve from dataProvider if not in Cache and Online


if (photoData == null && ConnectionManager.IsOnline)
{
EmployeeDataProvider dataProvider = new
EmployeeDataProvider();
photoData = dataProvider.GetEmployeePhotoData(employeeId);

cache.Add(employeeId.ToString(), photoData);
}

// No data found.
if (photoData == null)
return null;

// Convert bytes to Bitmap


using (MemoryStream ms = new MemoryStream(photoData))
{
return new Bitmap(ms);
}
}

Configure the persistent cache

1. Select the App.config file in the Solution Explorer. Select the View |
Open With… menu command. Select Enterprise Library
Configuration and click the OK button.
2. Select the Caching Application Block | Cache Managers | Cache
Manager node. Select the Action | New | Isolated Storage menu
command.

Document made for self preparation (Abhishek Maitrey) 32


Enterprise Library for .NET Framework 2.0 Hands On Labs

3. Set the PartitionName property to EmployeeBrowser.

Document made for self preparation (Abhishek Maitrey) 33


Enterprise Library for .NET Framework 2.0 Hands On Labs

The Partition Name allows multiple caches to share the same Isolated
storage location.

4. Save the configuration by selecting the menu File | Save All. Close
the configuration console.

Run the application

1. Select the Debug | Start Without Debugging menu command to


run the application.

Browse to a few of the employees, to load the cache with data, but
don't browse all the employees (e.g. don't browse to Fuller,
Dodsworth, or Callahan, so that their images are not cached). Close
the application when you are finished browsing.

2. Select the ConnectionManager.cs file in Solution Explorer. Select


the View | Code menu command. Modify the IsOnline property to
simulate the application being started offline.

static public bool IsOnline


{
get { return false; }
}

Normally this class would be responsible for testing server connectivity


to determine whether the client is online and can access the database.
See the Offline Application Block for ways to do this.

3. Select the Debug | Start Without Debugging menu command to


restart the application. The application is now offline and does not
access the database. Rather the employee contact details are
retrieved from the cache, as are the images of the employees you
browsed to while online. For the employees you had not browsed to
while online (e.g. Fuller, Dodsworth, and Callahan), no image is
displayed.
4. Close the application and close Visual Studio .NET.

To check the finished solution, open the EmployeeBrowser.sln file.

Exercise 3: Implement background caching

Document made for self preparation (Abhishek Maitrey) 34


Enterprise Library for .NET Framework 2.0 Hands On Labs

This exercise demonstrates the background loading of an offline cache.

First step

1. Open the EmployeeBrowser.sln file.

Implement background pre-loading of the cache when online

1. Select the EmployeeServices.cs in the Visual Studio Solution


Explorer. Select the View | Code menu command. Add the following
two methods, which will load the cache in the background.

private static void PopulateCache()


{
byte[] photoData = null;

EmployeesDataSet dsEmployees = GetContactDetails();

if (dsEmployees == null)
return;

CacheManager cache = CacheFactory.GetCacheManager();

foreach (EmployeesDataSet.EmployeesRow employee in


dsEmployees.Employees)
{
if (!cache.Contains(employee.EmployeeID.ToString()))
{
EmployeeDataProvider dataProvider = new
EmployeeDataProvider();
photoData =
dataProvider.GetEmployeePhotoData(employee.EmployeeID);

cache.Add(employee.EmployeeID.ToString(), photoData);
}

Document made for self preparation (Abhishek Maitrey) 35


Enterprise Library for .NET Framework 2.0 Hands On Labs

}
}

private delegate void PopulateCacheDelegate();

public static void BeginBackgroundLoad()


{
if (!ConnectionManager.IsOnline)
return;

PopulateCacheDelegate mi = new
PopulateCacheDelegate(PopulateCache);
mi.BeginInvoke(null, null);
}

The BeginBackgroundLoad method uses a delegate to begin the


PopulateCache method on a background thread, handled by the .NET
worker thread implementation.

The PopulateCache method iterates through all the employees to


retrieve and cache their image. Note that this is actually not a safe
activity if the user can add or remove rows in the dataset on another
thread (instead it would be better to Select the set of rows, and then
iterate through them).

The Caching Block guarantees us thread safety when using the Cache,
so it is safe to access from multiple threads at the same time.

2. Select the MainForm.cs file in Solution Explorer. Select the View |


Code menu command. Locate the MainForm_Load method and the
following code to start the background work.

private void MainForm_Load(object sender, EventArgs e)


{
this.ToolStripLabel1.Text = ConnectionManager.StatusText;

Document made for self preparation (Abhishek Maitrey) 36


Enterprise Library for .NET Framework 2.0 Hands On Labs

// Load data into the 'EmployeesDataSet'.


EmployeesDataSet tempDataset =
EmployeeService.GetContactDetails();

if (tempDataset != null)
this.EmployeesDataSet.Merge(tempDataset);

// TODO: Start loading cache in the background


EmployeeService.BeginBackgroundLoad();
}

Run the application

1. Select the Debug | Start Without Debugging menu command to


run the application.

Don't bother browsing to any other employees, but rather wait for at
least 10 seconds then exit the application.

While the application is online it will attempt to background cache the


employee images. The cache is persisted to Isolated Storage, but uses
a different PartitionName to the previous exercise.

2. Select the ConnectionManager.cs file in Solution Explorer. Select


the View | Code menu command. Modify the IsOnline property to
simulate the application being started offline.

static public bool IsOnline


{
get { return false; }
}

3. Select the Debug | Start Without Debugging menu command to


restart the application. The application is now offline and does not
access the database, however all employee contact details and images
should be cached.

Document made for self preparation (Abhishek Maitrey) 37


Enterprise Library for .NET Framework 2.0 Hands On Labs

More Information

1. For more information on how to use caching in building occasionally


connected solutions, see the Mobile Devices course which is part of the
Mastering Industrial Strength .NET series. This uses Enterprise Library
to support caching of reference data and Web service requests, using
both intrusive application code changes and proxy interception based
offline handling techniques.

To check the finished solution, open the EmployeeBrowser.sln file.

Copyright © 2005 Microsoft. All Rights Reserved.

Enterprise Library Hands On Labs

Document made for self preparation (Abhishek Maitrey) 38


Enterprise Library for .NET Framework 2.0 Hands On Labs

Lab 3: Enterprise Library Logging Hands


On Lab
After completing this lab, you will be able to:

• Use the Enterprise Library Logging Application Block to implement


logging in an application.
• Create and use custom TraceListeners.
• Create and use custom LogFormatters.

Scenario
This lab demonstrates the use of the Enterprise Library Logging Application
Block.

Estimated Time To Complete this lab: 30 minutes.

Exercise 1: Add Logging to an Application


In this exercise you will add logging and tracing to an existing application.
You will configure TraceListeners via the Enterprise Library Configuration
Tool.

First step

1. Open the EnoughPI.sln file.

About the application

1. Select the Debug | Start Without Debugging menu command to


run the application.

The EnoughPI application calculates the digits of pi (π, the ratio of the
circumference of a circle to its diameter). Enter your desired precision
via the NumericUpDown control and click the Calculate button. Be
prepared to wait if you want more than 500 digits of precision.

Document made for self preparation (Abhishek Maitrey) 39


Enterprise Library for .NET Framework 2.0 Hands On Labs

Adding Logging

1. Select the EnoughPI project. Select the Project | Add Reference


… menu command. Select the Browse tab and select the following
assembly located here.

• Microsoft.Practices.EnterpriseLibrary.Logging.dll.
2. Select the Calc\Calculator.cs file in Solution Explorer. Select the
View | Code menu command.

Add the following namespace inclusion at the top of the file:

using Microsoft.Practices.EnterpriseLibrary.Logging;

Document made for self preparation (Abhishek Maitrey) 40


Enterprise Library for .NET Framework 2.0 Hands On Labs

3. Log the calculation completion by adding the following code to the


OnCalculated method in the Calculator.cs file.

protected void OnCalculated(CalculatedEventArgs args)


{
// TODO: Log final result
LogEntry log = new LogEntry();
log.Message = string.Format("Calculated PI to {0} digits",
args.Digits);
log.Categories.Add(Category.General);
log.Priority = Priority.Normal;

Logger.Write(log);

if (Calculated != null)
Calculated(this, args);
}

Create a new LogEntry, set parameters, then use the Logger to write
the entry to one or more TraceListeners.

Notes:

•You have used constants for the Category and Priority rather
than use hard-coded tags and integers (see Constants.cs in the
EnoughPI.Logging project).
4. Log the calculation progress by adding the following code to the
OnCalculating method in the Calculator.cs file.

protected void OnCalculating(CalculatingEventArgs args)


{
// TODO: Log progress
Logger.Write(
string.Format("Calculating next 9 digits from {0}",
args.StartingAt),
Category.General,
Priority.Low
);

Document made for self preparation (Abhishek Maitrey) 41


Enterprise Library for .NET Framework 2.0 Hands On Labs

if (Calculating != null)
Calculating(this, args);

if (args.Cancel == true)
{
// TODO: Log cancellation
Logger.Write("Calculation cancelled by user!",
Category.General, Priority.High);
}
}

Notes:

•You have used an overload of the Write method on the Logger


class to shortcut creating a LogEntry.
5. Log calculation exceptions by adding the following code to the
OnCalculatorException method in the Calculator.cs file.

protected void OnCalculatorException(CalculatorExceptionEventArgs


args)
{
// TODO: Log exception
if (!(args.Exception is ConfigurationErrorsException))
{
Logger.Write(args.Exception, Category.General,
Priority.High);
}

if (CalculatorException != null)
CalculatorException(this, args);
}

Notes:

• You must test that the exception type is not a


ConfigurationErrorsException as you would not be able to
use the Logger if it has not be correctly configured.

Document made for self preparation (Abhishek Maitrey) 42


Enterprise Library for .NET Framework 2.0 Hands On Labs

• You would normally use the Enterprise Library Exception


Handling Application Block to create a consistent strategy for
processing exceptions.

Enterprise Library Configuration

1. We will use the Enterprise Library Configuration tool to configure our


application. You may either start this tool from the Windows Start
menu (select All Programs | Microsoft patterns and practices |
Enterprise Library | Enterprise Library Configuration) and open
the App.config file located here.

Alternatively you may configure Visual Studio to open the configuration


file with the tool, as described below.

2. Select the App.config file in the Solution Explorer. Select the View |
Open With… menu command. The OpenWith dialog is displayed.
Click the Add button.

3. In the Add Program dialog, set the Program name to the


EntLibConfig.exe file found here. Set the Friendly name to
Enterprise Library Configuration. Click the OK button.

Document made for self preparation (Abhishek Maitrey) 43


Enterprise Library for .NET Framework 2.0 Hands On Labs

Visual Studio will pass the configuration file (App.config) to the


EntLibConfig.exe program as a command line parameter.

4. In the Open With dialog, select the newly entered Enterprise


Library Configuration program and click the OK button.

Configure the application

Document made for self preparation (Abhishek Maitrey) 44


Enterprise Library for .NET Framework 2.0 Hands On Labs

1. Right click on the Application and select New | Logging Application


Block.

2. The default Logging Application Block configuration defines a


Category Source named General. Categories are simply text tags
that you may apply to your log events to group them. The General
category has one TraceListener reference (named Formatted EventLog
TraceListener).

New categories may be added by right clicking on the Category


Sources node and selecting New | Category. A category may have
many TraceListener references (though none repeated), and a
TraceListener may be referenced by many categories.

Document made for self preparation (Abhishek Maitrey) 45


Enterprise Library for .NET Framework 2.0 Hands On Labs

3. Select the Logging Application Block | Trace Listeners |


Formatted EventLog TraceListener node.

Set the Source property to EnoughPI.

Document made for self preparation (Abhishek Maitrey) 46


Enterprise Library for .NET Framework 2.0 Hands On Labs

This TraceListener will log formatted entries (using the Text Formatter)
to the windows event log.

4. Select the File | Save All menu command to save the application
configuration. Close the Enterprise Library Configuration tool.

Run the application

1. Select the Debug | Start Without Debugging menu command to


run the application. Enter your desired precision and click the
Calculate button.
2. Run the Event Viewer. From the Windows Start menu select
Administrative Tools l Event Viewer. View the Application log for
messages from the EnoughPI source.

Document made for self preparation (Abhishek Maitrey) 47


Enterprise Library for .NET Framework 2.0 Hands On Labs

3. Double click on a log entry to view the formatted log message.

Document made for self preparation (Abhishek Maitrey) 48


Enterprise Library for .NET Framework 2.0 Hands On Labs

4. Exit the application.

Adding Tracing

1. Often you would like to time sections of our application. The Logging
and Instrumentation Application Block includes tracing which allows us
to book-end a section of code and log the execution time.
2. Select the Calc\Calculator.cs file in the Solution Explorer. Select the
View | Code menu command.

public string Calculate(int digits)


{
StringBuilder pi = new StringBuilder("3", digits + 2);
string result = null;

try
{
if (digits > 0)

Document made for self preparation (Abhishek Maitrey) 49


Enterprise Library for .NET Framework 2.0 Hands On Labs

{
// TODO: Add Tracing around the calculation
using (new Tracer(Category.Trace))
{
pi.Append(".");
for (int i = 0; i < digits; i += 9)
{
CalculatingEventArgs args;
args = new CalculatingEventArgs(pi.ToString(), i+1);
OnCalculating(args);

// Break out if cancelled


if (args.Cancel == true) break;

// Calculate next 9 digits


int nineDigits = NineDigitsOfPi.StartingAt(i+1);
int digitCount = Math.Min(digits - i, 9);
string ds = string.Format("{0:D9}", nineDigits);
pi.Append(ds.Substring(0, digitCount));
}
}
}

result = pi.ToString();

// Tell the world I've finished!


OnCalculated(new CalculatedEventArgs(result));
}
catch (Exception ex)
{
// Tell the world I've crashed!
OnCalculatorException(new CalculatorExceptionEventArgs(ex));
}

Document made for self preparation (Abhishek Maitrey) 50


Enterprise Library for .NET Framework 2.0 Hands On Labs

return result;
}

Often you would like to time sections of our application. Tracing allows
us to book-end a section of code and log the execution time.

The Tracer will stop timing, and log its end trace message, when it is
disposed. The using block guarantees us that Dispose() will be
called on the Tracer at the end of the block. Allowing the Garbage
Collector to dispose of the Tracer will result in incorrect timings.

3. Select the App.config file in the Solution Explorer. Select the View |
Open With… menu command. Select Enterprise Library
Configuration and click the OK button.
4. Select the Logging Application Block node. Set the
TracingEnabled property to True.

Document made for self preparation (Abhishek Maitrey) 51


Enterprise Library for .NET Framework 2.0 Hands On Labs

5. Add a new TraceListener. Select the Logging Application Block |


Trace Listeners node. Select the Action | New | FlatFile
TraceListener menu command.

6. Set the following properties:

• Formatter = Text Formatter.

Document made for self preparation (Abhishek Maitrey) 52


Enterprise Library for .NET Framework 2.0 Hands On Labs

7. Add a new Trace category. Select the Logging Application Block |


Category Sources node. Select the Action | New | Category menu
command.

Document made for self preparation (Abhishek Maitrey) 53


Enterprise Library for .NET Framework 2.0 Hands On Labs

8. Set the following properties:

• Name = Trace, and


• SourceLevels = ActivityTracing.

Document made for self preparation (Abhishek Maitrey) 54


Enterprise Library for .NET Framework 2.0 Hands On Labs

The category name "Trace" was used in our code (see Constants.cs in
the EnoughPI.Logging project). Using the ActivityTracing source
level will restrict the trace logging to the start and end log entries only.

9. Right click on the new Trace category, and select the New | Trace
Listener Reference menu command, and set the following property:

• ReferencedTraceListener = FlatFile TraceListener.

Document made for self preparation (Abhishek Maitrey) 55


Enterprise Library for .NET Framework 2.0 Hands On Labs

10. Select the File | Save All menu command to save the application
configuration. Close the Enterprise Library Configuration tool.
11. Select the Debug | Start Without Debugging menu command to
run the application. Enter your desired precision and click the
Calculate button.
12. You may view the elapsed time for the trace in the trace.log file.

----------------------------------------

Timestamp: 13/12/2005 6:08:01 AM

Message: Start Trace: Activity '8c07ce3b-235b-4a51-bdcc-83a5997c989e' in method


'Calculate' at 71661842482 ticks

Category: Trace

Priority: 5

EventId: 1

Severity: Start

Document made for self preparation (Abhishek Maitrey) 56


Enterprise Library for .NET Framework 2.0 Hands On Labs

Title:TracerEnter

Machine: TAGGERT

Application Domain: EnoughPI.exe

Process Id: 6016

Process Name: C:\Program Files\Microsoft Enterprise


Library\labs\cs\Logging\exercises\ex01\begin\EnoughPI\bin\Debug\EnoughPI.exe

Win32 Thread Id: 6092

Thread Name:

Extended Properties:

----------------------------------------

----------------------------------------

Timestamp: 13/12/2005 6:08:01 AM

Message: End Trace: Activity '8c07ce3b-235b-4a51-bdcc-83a5997c989e' in method


'Calculate' at 71662624219 ticks (elapsed time: 0.218 seconds)

Category: Trace

Priority: 5

EventId: 1

Severity: Stop

Title:TracerExit

Machine: TAGGERT

Application Domain: EnoughPI.exe

Process Id: 6016

Process Name: C:\Program Files\Microsoft Enterprise


Library\labs\cs\Logging\exercises\ex01\begin\EnoughPI\bin\Debug\EnoughPI.exe

Win32 Thread Id: 6092

Thread Name:

Document made for self preparation (Abhishek Maitrey) 57


Enterprise Library for .NET Framework 2.0 Hands On Labs

Extended Properties:

----------------------------------------

Your file should look similar to the above output.

13.Close the application and Visual Studio.

To check the finished solution, open the EnoughPI.sln file.

Exercise 2: Create and use a custom Trace Listener


In this exercise you will build a custom Trace Listener to send formatted log
entries to the Console standard output. You will then add this new Trace
Listener to the EnoughPI application, and monitor the log entries in real-
time.

First step

1. Open the EnoughPI.sln file.

Create a custom Trace Listener

1. Select the EnoughPI.Logging project. Select the Project | Add


Reference… menu command. Select the Browse tab and select the
following assemblies located here.

• Microsoft.Practices.EnterpriseLibrary.Common.dll, and
• Microsoft.Practices.EnterpriseLibrary.Logging.dll.
2. Select the TraceListeners\ConsoleTraceListener.cs file in the
Solution Explorer. Select the View | Code menu command. Add the
following namespaces:

using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Logging;
using Microsoft.Practices.EnterpriseLibrary.Logging.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Logging.Formatters;
using Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners;

3. Add the following code to the ConsoleTraceListener class.

Document made for self preparation (Abhishek Maitrey) 58


Enterprise Library for .NET Framework 2.0 Hands On Labs

[ConfigurationElementType(typeof(CustomTraceListenerData))
]
public class ConsoleTraceListener : CustomTraceListener
{
public ConsoleTraceListener()
: base()
{
}

public override void TraceData(TraceEventCache eventCache,

string source, TraceEventType eventType, int id, object


data)
{
if (data is LogEntry && this.Formatter != null)
{
this.WriteLine(this.Formatter.Format(data as
LogEntry));
}
else
{
this.WriteLine(data.ToString());
}
}

public override void Write(string message)


{
Console.Write(message);
}

public override void WriteLine(string message)


{
// Delimit each message
Console.WriteLine((string)this.Attributes["delimiter"]);

Document made for self preparation (Abhishek Maitrey) 59


Enterprise Library for .NET Framework 2.0 Hands On Labs

// Write formatted message


Console.WriteLine(message);
}
}

Note: The base class is CustomTraceListener, which mandates


that you override two abstract methods - Write(string message)
and WriteLine(string message). However to format the message
we need to override the TraceData method.

The ConsoleTraceListener is expecting a parameter, "delimiter", as


part of the listener configuration.

4. Copy the output assembly to [Enterprise install directory]\bin.

Select the EnoughPI.Logging project. Select the Project |


EnoughPI.Logging Properties… menu command, and select the
Build Events tab. Add the following command as the Post-build
event command line.

copy "$(TargetPath)" "..\..\..\..\..\..\..\..\..\bin"

Document made for self preparation (Abhishek Maitrey) 60


Enterprise Library for .NET Framework 2.0 Hands On Labs

The Enterprise Library Configuration tool will automatically load


assemblies in the same directory.

5. Select the File | Save All menu command.


6. Select the Build | Build Solution menu command, to compile the
complete solution.

Using a custom TraceListener

1. Select the EnoughPI project App.config file in the Solution Explorer.


Select the View | Open With… menu command. Select Enterprise
Library Configuration and click the OK button.
2. Select the Logging Application Block | Trace Listeners node.
Select the Action | New | Custom Trace Listener menu command.

Document made for self preparation (Abhishek Maitrey) 61


Enterprise Library for .NET Framework 2.0 Hands On Labs

3. Set the following property:

• Formatter = Text Formatter.


4. Select the Type property, and click the ellipses to display the Type
Selector dialog.

5. Select the ConsoleTraceListener class from the EnoughPI.Logging


assembly and click the Ok button.

Document made for self preparation (Abhishek Maitrey) 62


Enterprise Library for .NET Framework 2.0 Hands On Labs

The Type Selector lists class, from assemblies in the same directory
as the Enterprise Library Configuration tool, which inherit from
CustomTraceListener and have a ConfigurationElementType of
CustomTraceListenerData.

6. Select the Attributes property and click the ellipses to display the
EditableKeyValue Collection Editor.

7. Click the Add button to add a new key/value pair.

• Key = delimiter, and


• Value = "---------------------------"

Document made for self preparation (Abhishek Maitrey) 63


Enterprise Library for .NET Framework 2.0 Hands On Labs

Click the Ok button.

Note: You will remember our ConsoleTraceListener is expecting a


parameter named delimiter, which is printed before each
formatted log entry is written to the console.

8. Select the Logging Application Block | Category Sources |


General node. Select the Action | New | Trace Listener
Reference menu command.

Document made for self preparation (Abhishek Maitrey) 64


Enterprise Library for .NET Framework 2.0 Hands On Labs

9. Set the following property:

• ReferencedTraceListener = Custom TraceListener.

Document made for self preparation (Abhishek Maitrey) 65


Enterprise Library for .NET Framework 2.0 Hands On Labs

10. Select the File | Save All menu command, and close the Enterprise
Library Configuration tool.

Note: If you don't close the Enterprise Library Configuration tool you
will get a build error next time you build the EnoughPI.Logging post
build event will fail.

View the TraceListener output

1. Select the EnoughPI project. Select the Project | EnoughPI


Properties… menu command, and select the Application tab and
set:

• Output type = Console Application.

2. Select the File | Save All menu command.


3. Select the Debug | Start Without Debugging menu command to
run the application. Enter your desired precision and click the
Calculate button. The log entries will be displayed in the applications
Console Window.

Document made for self preparation (Abhishek Maitrey) 66


Enterprise Library for .NET Framework 2.0 Hands On Labs

To check the finished solution, open the EnoughPI.sln file.

Exercise 3: Create and use a custom LogFormatter


In this exercise you will add a custom LogFormatter to a logging application.

First step

1. Open the EnoughPI.sln file.

Create a custom log formatter

1. Select the Formatters\XmlFormatter.cs file in the Solution


Explorer. Select the View | Code menu command. Add the following
namespaces:

using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Logging;
using Microsoft.Practices.EnterpriseLibrary.Logging.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Logging.Formatters;

2. Add the following code to the XmlFormatter class.

Document made for self preparation (Abhishek Maitrey) 67


Enterprise Library for .NET Framework 2.0 Hands On Labs

[ConfigurationElementType(typeof(CustomFormatterData))]
public class XmlFormatter : LogFormatter
{
private NameValueCollection Attributes = null;

public XmlFormatter(NameValueCollection attributes)


{
this.Attributes = attributes;
}

public override string Format(LogEntry log)


{
string prefix = this.Attributes["prefix"];
string ns = this.Attributes["namespace"];

using (StringWriter s = new StringWriter())


{
XmlTextWriter w = new XmlTextWriter(s);
w.Formatting = Formatting.Indented;
w.Indentation = 2;

w.WriteStartDocument(true);
w.WriteStartElement(prefix, "logEntry", ns);
w.WriteAttributeString("Priority", ns,
log.Priority.ToString(CultureInfo.InvariantCulture));
w.WriteElementString("Timestamp", ns,
log.TimeStampString);
w.WriteElementString("Message", ns, log.Message);
w.WriteElementString("EventId", ns,
log.EventId.ToString(CultureInfo.InvariantCulture));
w.WriteElementString("Severity", ns,
log.Severity.ToString());
w.WriteElementString("Title", ns, log.Title);
w.WriteElementString("Machine", ns,
log.MachineName);
w.WriteElementString("AppDomain", ns,
log.AppDomainName);
w.WriteElementString("ProcessId", ns, log.ProcessId);

Document made for self preparation (Abhishek Maitrey) 68


Enterprise Library for .NET Framework 2.0 Hands On Labs

w.WriteElementString("ProcessName", ns,
log.ProcessName);
w.WriteElementString("Win32ThreadId", ns,
log.Win32ThreadId);
w.WriteElementString("ThreadName", ns,
log.ManagedThreadName);
w.WriteEndElement();
w.WriteEndDocument();

return s.ToString();
}
}
}

The log entry will be formatted as XML. Two parameters are expected
(prefix, and namespace).

3. Select Build | Build Solution to compile the complete solution.

Use a custom log formatter

1. Select the EnoughPI project App.config file in the Solution Explorer.


Select the View | Open With… menu command. Select Enterprise
Library Configuration and click the OK button.
2. Select the Logging Application Block | Formatters node. Select
the Action | New | Custom Formatter menu command. Set the
following property:

• Name = Xml Formatter.

Document made for self preparation (Abhishek Maitrey) 69


Enterprise Library for .NET Framework 2.0 Hands On Labs

3. Select the Type property, and click the ellipses to display the Type
Selector dialog.

4. Select the XmlFormatter class from the EnoughPI.Logging


assembly and click the Ok button.

Document made for self preparation (Abhishek Maitrey) 70


Enterprise Library for .NET Framework 2.0 Hands On Labs

The Type Selector lists class, from assemblies in the same directory
as the Enterprise Library Configuration tool, which inherit from
LogFormatter and have a ConfigurationElementType of
CustomFormatterData.

5. Select the Attributes property and click the ellipses to display the
EditableKeyValue Collection Editor.

6. Add the following Key/Value pairs:

• Key = prefix, Value = x, and


• Key = namespace, Value = EnoughPI/2.0

Click the Ok button.

Document made for self preparation (Abhishek Maitrey) 71


Enterprise Library for .NET Framework 2.0 Hands On Labs

Note: You will remember our XmlFormatter is expecting two


parameters, the prefix and namespace for the XML document.

7. Select the Logging Application Block | Trace Listeners | Custom


TraceListener node. Set the following property:

• Formatter = Xml Formatter.

Document made for self preparation (Abhishek Maitrey) 72


Enterprise Library for .NET Framework 2.0 Hands On Labs

8. Select the File | Save All menu command, and close the Enterprise
Library Configuration tool.
9. Select the Debug | Start Without Debugging menu command to
run the application. Enter your desired precision and click the
Calculate button. The log entries will be displayed in the applications
Console Window.

More information

1. For more information on how and when to instrument applications,


including using custom request tracing to identify issues across multi-
tiered applications, see "Using Advanced Microsoft® .NET Performance
and Operational Techniques" course which is part of the Mastering
Industrial Strength .NET series. This course shows how to build custom
providers for the enterprise logging block and also extends Enterprise
Library to support request tracing across Web services, with a
mechanism that would inter-operate with non-Microsoft technologies.
The course also uses some freely available profiling tools to help solve
performance issues once a bottleneck has been identified.

To check the finished solution, open the EnoughPI.sln file.

Copyright © 2005 Microsoft. All Rights Reserved.

Document made for self preparation (Abhishek Maitrey) 73


Enterprise Library for .NET Framework 2.0 Hands On Labs

Enterprise Library Hands On Labs


Lab 4: Exception Handling Application
Block
After completing this lab, you will be able to:

• Add Exception Logging to an application.


• Use a Replace Handler to hide sensitive information.

Scenario
This lab demonstrates the use of the Enterprise
Library Exception Handling Application Block.

Estimated Time To Complete this lab: 30 minutes.

Exercise 1: Logging Exceptions


In this exercise you will take an application without exception handling, and
add local and global exception handlers that log the exceptions to the Event
Log using the Exception Handling Application Block.

First step

1. Open the Puzzler.sln file.

Review the Application

1. This application performs two functions, it checks the spelling of words


against a dictionary (unix dict for size) and it uses the dictionary to
generate a list of words that can be constructed from a character list.
2. Select the Debug | Start Debugging menu command to run
the application.

There is currently no exception handling in the application. Attempt to


add a word which contains numbers to the dictionary (type "ab123" in

Document made for self preparation (Abhishek Maitrey) 74


Enterprise Library for .NET Framework 2.0 Hands On Labs

the word to check textbox and click Add Word). An unhandled


exception will occur, which will break into the debugger.

Select the Debug | Stop Debugging menu command to exit the


application and return to Visual Studio.

Add Try/Catch Exception Handling

1. Select the PuzzlerUI project. Select the Project | Add Reference


… menu command. Select the Browse tab and select the following
assembly located here.

• Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.dll.

While this assembly is the only assembly required for the


ExceptionHandling API, other assemblies may need to be available in
the bin\debug directory to provide specific exception handling
functionality, which you will add later.

2. Select the Puzzler.cs file in the Solution Explorer. Select the View |
Code menu command.

Add the following namespace inclusion at the top of the file:

using Microsoft.Practices.EnterpriseLibrary.ExceptionHandling;

3. Find the btnAddWord_Click method, and add a try/catch section


around the AddWord and SetError calls. (Inserted code in bold):

private void btnAddWord_Click(object sender, System.EventArgs e)


{
try
{
// TODO: Handle exceptions
PuzzlerService.Dictionary.AddWord(txtWordToCheck.Text);
errorProvider1.SetError(txtWordToCheck, "");
}
catch (Exception ex)

Document made for self preparation (Abhishek Maitrey) 75


Enterprise Library for .NET Framework 2.0 Hands On Labs

{
bool rethrow = ExceptionPolicy.HandleException(ex, "UI
Policy");
if (rethrow)
throw;

MessageBox.Show(string.Format(
"Failed to add word {0}, please contact support.",
txtWordToCheck.Text));
}
}

NOTE: It is very important to just use the throw statement, rather


than throw ex. If you have "throw ex", then the stack trace of the
exception will be replaced with a stack trace starting at the re-throw
point, which is usually not the desired effect.

Enterprise Library Configuration Tool

1. Add a new Application configuration file (App.config) to the PuzzlerUI


project.

Click on the PuzzlerUI project. Select the Project| Add New


Item… menu command. Select Application configuration file
template. Leave the Name as App.config.

Document made for self preparation (Abhishek Maitrey) 76


Enterprise Library for .NET Framework 2.0 Hands On Labs

2. We will use the Enterprise Library Configuration tool to configure our


application. You may either start this tool from the Windows Start
menu (select All Programs | Microsoft patterns and practices |
Enterprise Library | Enterprise Library Configuration) and open
the App.config file located here.

Alternatively you may configure Visual Studio to open the configuration


file with the tool, as described below.

3. Select the App.config file in the Solution Explorer. Select the View |
Open With… menu command. The OpenWith dialog is displayed.
Click the Add button.

Document made for self preparation (Abhishek Maitrey) 77


Enterprise Library for .NET Framework 2.0 Hands On Labs

4. In the Add Program dialog, set the Program name to the


EntLibConfig.exe file found here. Set the Friendly name to
Enterprise Library Configuration. Click the OK button.

Visual Studio will pass the configuration file (App.config) to the


EntLibConfig.exe program as a command line parameter.

5. In the Open With dialog, select the newly entered Enterprise


Library Configuration program and click the OK button.

Document made for self preparation (Abhishek Maitrey) 78


Enterprise Library for .NET Framework 2.0 Hands On Labs

Configure the Application to Use Exception Management

1. Right click on the Application and select New | Exception Handling


Application Block.

Document made for self preparation (Abhishek Maitrey) 79


Enterprise Library for .NET Framework 2.0 Hands On Labs

2. Select the Exception Handling Application Block node. Select the


Action | New | Exception Policy menu command. Set following
property:

• Name = UI Policy.

The policy name here must match that specified in the code.
Typically you would use constants to help prevent typographical errors,
especially since the exception handling typically is not tested as
thoroughly as normal code paths.

3. Select the UI Policy node. Select the Action | New | Exception


Type menu command.

This will open the Type Selector dialog. Select the


System.Exception (the default) and click the Ok button.

Document made for self preparation (Abhishek Maitrey) 80


Enterprise Library for .NET Framework 2.0 Hands On Labs

This is a filter that specifies which exceptions should be processed by


the exception handling code, and what handlers to run. In this case, all
exceptions derived from System.Exception will be processed.

4. Set the following property for the System.Exception type:

• PostHandlingAction = None.

Document made for self preparation (Abhishek Maitrey) 81


Enterprise Library for .NET Framework 2.0 Hands On Labs

This will cause all exceptions to be handled internally within the


exception handling code, and the caller will not be requested to re-
throw the exception with its catch block.

5. Select the Exception Handling Application Block | UI Policy |


Exception node. Select the Action | New | Logging Handler menu
command.

Document made for self preparation (Abhishek Maitrey) 82


Enterprise Library for .NET Framework 2.0 Hands On Labs

Note: This automatically includes the Logging Application Block in


your configuration.

6. Select the Exception Handling Application Block | UI Policy |


Exception | Logging Handler node. Set the following properties:

• FormatterType = TextExceptionFormatter, and


• LogCategory = General.

Document made for self preparation (Abhishek Maitrey) 83


Enterprise Library for .NET Framework 2.0 Hands On Labs

7. Select the File | Save All menu command to save the application
configuration. Close the Enterprise Library Configuration tool.

Click on Yes in the dialog box warning about the app.config being
modified outside the source editor.

Change the application to include the exception logging assembly

1. Select the PuzzlerUI project. Select the Project | Add Reference


… menu command. Select the Browse tab and select the following
assembly located here.

• Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging.
dll.

Document made for self preparation (Abhishek Maitrey) 84


Enterprise Library for .NET Framework 2.0 Hands On Labs

Because one of the goals of the Enterprise Library is to keep the blocks
de-coupled, it is possible to use the Exception Handling block without
needing the Logging block (e.g. by creating your own exception
handler). If you want to use the two blocks together, then you need to
use this assembly, which contains an Exception Handler that logs via
the logging block.

Run the Application

1. Select the Debug | Start Without Debugging menu command to


run the application.

Try adding a number (type a number in the Word to check text box,
and click Add Word) - a MessageBox is displayed with an error
- "Failed to add word …, please contact support".

2. Check the Event Log by using the Event Viewer (Control Panel |
Administrative Tools | Event Viewer). Look at the top of the
Application Log. The exception will be logged.

Document made for self preparation (Abhishek Maitrey) 85


Enterprise Library for .NET Framework 2.0 Hands On Labs

After the previous exception the Exception Management Block will


have written an entry in the Application Event Log using the Logging
Block.

3. Close the application.

Add Global Exception Handling

1. While it is possible to put try/catch sections around all the event


handlers in an application, it is usually better to provide a single
generic handler that fires whenever an unhandled exception occurs
within the application.
2. Select the Puzzler.cs file in the Solution Explorer. Select the View |
Code menu command. Locate the btnAddWord_Click method, and
remove the exception handling code added earlier.

Document made for self preparation (Abhishek Maitrey) 86


Enterprise Library for .NET Framework 2.0 Hands On Labs

private void btnAddWord_Click(object sender, System.EventArgs e)


{
PuzzlerService.Dictionary.AddWord(txtWordToCheck.Text);
errorProvider1.SetError(txtWordToCheck, "");
}

3. Select the Startup.cs file in the Solution Explorer. Select the View |
Code menu command. Add the following namespace inclusion at the
top of the file:

Application execution begins here. There are two events you can use
to listen for unhandled exceptions:

The Application.ThreadException event is raised when an


unhandled exception occurs on the thread that is executing the
Application.Run method.

If an exception is raised during that handler, or occurs on a different


thread to the UI, then the AppDomain.UnhandledException event
will fire.

using Microsoft.Practices.EnterpriseLibrary.ExceptionHandling;

4. Add the following method to handle exceptions in the Startup class.

public static void HandleException(Exception ex, string policy)


{
Boolean rethrow = false;
try
{
rethrow = ExceptionPolicy.HandleException(ex, policy);
}
catch (Exception innerEx)
{
string errorMsg = "An unexpected exception occured while " +
"calling HandleException with policy '" + policy + "'. ";
errorMsg += Environment.NewLine + innerEx.ToString();

Document made for self preparation (Abhishek Maitrey) 87


Enterprise Library for .NET Framework 2.0 Hands On Labs

MessageBox.Show(errorMsg, "Application Error",


MessageBoxButtons.OK, MessageBoxIcon.Stop);

throw ex;
}

if (rethrow)
{
// WARNING: This will truncate the stack of the exception
throw ex;
}
else
{
MessageBox.Show("An unhandled exception occurred and has "
+
"been logged. Please contact support.");
}
}

This method will use the exception handling block, and will also display
valid information if there is a problem with the exception handling
block itself (e.g. missing configuration).

It will also display a message to the user if the exception is swallowed


(i.e. not re-thrown).

5. Add the following method as the event handler to the Application


ThreadException event.

static void Application_ThreadException(object sender,


ThreadExceptionEventArgs e)
{
HandleException(e.Exception, "UI Policy");
}

This event handler will use the policy (UI Policy) that you defined
before for the UI layer. In the next exercise you will customize this
policy to allow certain types of exception to "escape" and shut the
application down.

Document made for self preparation (Abhishek Maitrey) 88


Enterprise Library for .NET Framework 2.0 Hands On Labs

6. Add an event handler for the AppDomain UnhandledException


event.

static void CurrentDomain_UnhandledException(object sender,


UnhandledExceptionEventArgs e)
{
if (e.ExceptionObject is System.Exception)
{
HandleException((System.Exception)e.ExceptionObject,
"Unhandled Policy");
}
}

This handler will use a new policy, named Unhandled Policy, which
will set up in the next exercise. The Unhandled Policy should almost
always just log the exception, and not re-throw.

7. Connect the event handlers to the events at the beginning of the


application by including the following code in the Main method
(Inserted code in bold).

static void Main()


{
// TODO: Handle unhandled exceptions
Application.ThreadException +=
new
ThreadExceptionEventHandler(Application_ThreadException);

AppDomain.CurrentDomain.UnhandledException +=
new
UnhandledExceptionEventHandler(CurrentDomain_UnhandledE
xception);

Puzzler f = new Puzzler();


Application.Run(f);
}

8. Select the Debug | Start Without Debugging menu command to


run the application.

Document made for self preparation (Abhishek Maitrey) 89


Enterprise Library for .NET Framework 2.0 Hands On Labs

Try adding a number (type a number in the Word to check text box
and click Add Word) - a MessageBox is displayed - "An unhandled
exception occurred and has been logged. Please contact support.".
Look in the event log for the logged exception.

9. Close the application and Visual Studio.

To check the finished solution, open the Puzzler.sln file.

Exercise 2: Exception Handling Strategies


In this exercise you will secure part of our application service with Code
Access Security and then use a Replace Handler with the Exception
Handling Application Block to hide sensitive information from clients. You will
also see how you can filter which exceptions escape the top application layer.

First step

1. Open the Puzzler2.sln file.

View the Service Modifications

1. Select the PuzzlerService project DictionaryService.cs file in the


Solution Explorer. Select the View | Code menu command.

This class acts as a Service Interface on top of the Dictionary class.


Within this class you provide exception filtering and transformation
before sending the results back to the client. For techniques to
intercept the call and automatically transform and handle exceptions,
see the "Developing Microsoft® .NET Service-Oriented
Applications" course of Mastering Industrial Strength .NET.

Protect the Service's 'Add Word' Functionality with Code Access Security

1. Select the PuzzlerService project Dictionary.cs file in the Solution


Explorer. Select the View | Code menu command. Locate the
AddWord method and decorate it with a security attribute as follows:

// TODO: Add security attribute


[PrincipalPermission(SecurityAction.Demand, Role = "Grand
PoohBah")]
public static Boolean AddWord(string wordToAdd)

Document made for self preparation (Abhishek Maitrey) 90


Enterprise Library for .NET Framework 2.0 Hands On Labs

{
if (!IsWord(wordToAdd))
{
// It is not alphabetic! Throw an exception
throw new ApplicationException(
"Word to add does not consist of alphabetic letters");
}
if (Dict[wordToAdd] == null)
{
Dict.Add(wordToAdd, wordToAdd);
}
return true;
}

This method can now only be executed by a member of the role Grand
PoohBah, an unlikely situation.

Note: Decorate the AddWord method in Dictionary.cs not


DictionaryService.cs.

2. Select the Debug | Start Without Debugging menu command to


run the application.

Type a nonsense word (alphabetic - no numbers!) into the 'Word To


Check' textbox (ensure that you have an error flashing), then click on
the Add Word button. This will call the service's AddWord function
and throw a SecurityException, which you can check in the event
viewer.

Document made for self preparation (Abhishek Maitrey) 91


Enterprise Library for .NET Framework 2.0 Hands On Labs

The SecurityException may be serialized from a Server to a Client


(over Web Services) and contains information that may help an
attacker break our security. You would prefer to catch and log the
security exception on the server, then pass an exception containing
less information to the client.

3. Close the application.

Configure the application to replace SecurityExceptions

1. Select the PuzzlerUI project App.config file in the Solution Explorer.


Select the View | Open With… menu command. Select Enterprise
Library Configuration and click the OK button.

The App.config file already has an empty policy, named Service


Policy. By default, if a policy is empty, then exceptions will just be re-
thrown inside the catch block, so in effect the policy will do nothing.

Document made for self preparation (Abhishek Maitrey) 92


Enterprise Library for .NET Framework 2.0 Hands On Labs

2. Select the Service Policy node. Select the Action | New |


Exception Type menu command. Select the
System.Security.SecurityException type (from mscorlib) and click
the Ok button.

3. Select the Service Policy | SecurityException node and set the


following property:

• PostHandlingAction = ThrowNewException.

Document made for self preparation (Abhishek Maitrey) 93


Enterprise Library for .NET Framework 2.0 Hands On Labs

4. Add a new Logging Handler. Select the Service Policy


| SecurityException node. Select the Action | New | Logging
Handler menu command. Set the following properties:

• FormatterType = TextExceptionFormatter,
• LogCategory = General, and
• Title = Security Exception in Service Layer.

Document made for self preparation (Abhishek Maitrey) 94


Enterprise Library for .NET Framework 2.0 Hands On Labs

5. Add a new Replace Handler. Select the Service Policy |


SecurityException node. Select the Action | New | Replace
Handler menu command. Set the following properties:

• ExceptionMessage = Unauthorized Access, and


• ReplaceExceptionType =
System.Security.SecurityException (from mscorlib).

Document made for self preparation (Abhishek Maitrey) 95


Enterprise Library for .NET Framework 2.0 Hands On Labs

Although you have kept the type the same, by creating a new
SecurityException, this will not provide the client any of the stack
information or internal security exception information, which could
compromise security.

Change the Application to Exit on a Security Exception

1. Select the UI Policy node. Select the Action | New | Exception


Type menu command. Select the
System.Security.SecurityException type (from mscorlib) and click
the Ok button. Set the following property:

• PostHandlingAction = NotifyRethrow.

Document made for self preparation (Abhishek Maitrey) 96


Enterprise Library for .NET Framework 2.0 Hands On Labs

A PostHandlingAction of NotifyRethrow, will cause the handler for the


Application.ThreadException event to re-throw the exception. The re-
thrown exception will be an unhandled exception, and .NET will be
forced to shut down the application.

2. Add a new Logging Handler to the SecurityException exception


type under the UI Policy. Select the Action | New | Logging
Handler menu command. Set the following properties:

• FormatterType = TextExceptionFormatter,
• LogCategory = General, and
• Title = Security Exception in UI Layer.

Document made for self preparation (Abhishek Maitrey) 97


Enterprise Library for .NET Framework 2.0 Hands On Labs

3. Select the File | Save All menu command to save the application
configuration. Close the Enterprise Library Configuration tool.

Test the Replace Handler

1. Select the Debug | Start Without Debugging menu command to


run the application.

Type a nonsense (alphabetic) word into the Word To Check textbox


(ensure that you have an error flashing), then click on the Add Word
button. If debugging click on Continue when it displays an
"Unhandled exception" message. Open the event log to look at the
events created. You can use the debugger to observe exactly what is
happening and relate this to the Exception Handling Policies.

This time the Exception will be shown three times in the Event Log.

Document made for self preparation (Abhishek Maitrey) 98


Enterprise Library for .NET Framework 2.0 Hands On Labs

First a SecurityException is thrown in Dictionary.cs. This is caught by


the service layer (DictionaryService.cs) which applies Service Policy.
This will cause the exception to be written to the event log on the
server (with all available information included) and then will capture a
new replacement SecurityException (without specific stack
information).

Second the replacing SecurityException is caught by the Application


ThreadException handler in Startup.cs. This applies UI Policy which
will write the exception to the event log on the client (the same
machine in our case) and set the re-throw boolean to true which
allows our code to decide to re-throw the second SecurityException.

Third the re-thrown SecurityException is caught by our AppDomain


UnhandledException handler (it was thrown from outside the
Application.Run) which applies Unhandled Policy. This will log the
exception and display a MessageBox informing us that there was an
error in the application.

The AppDomain UnhandledException handler does not consume


exceptions, so the exception continues to pass to the runtime or
debugger exception handler. This will cause a standard unhandled
exception dialog box to be displayed.

To check the finished solution, open the Puzzler2.sln file.

Copyright © 2005 Microsoft. All Rights Reserved.

Document made for self preparation (Abhishek Maitrey) 99


Enterprise Library for .NET Framework 2.0 Hands On Labs

Enterprise Library Hands On Labs


Lab 5: Enterprise Library Cryptography
Application Block
After completing this lab, you will be able to:

• Keep non configuration data secret.


• Store passwords in a secure manner.

Scenario
This lab demonstrates the use of the Enterprise Library Cryptography Block.
Keeping secrets is both important and difficult. Probably the most common
secrets you wish to keep are connection strings that often include usernames
and passwords, however the task of securing these is handled for us by the
Configuration Application Block and was discussed in the Data Access topic
earlier. This lab looks at securing non configuration data and using hashing
to secure passwords.

Estimated Time To Complete this lab: 30 minutes.

Exercise 1: Encrypt and Decrypt secrets


In this exercise you will look at protecting information that is not part of our
configuration. As an example you will create an application that simulates a
chat (Messenger) application and upgrade it to communicate using
encrypted rather than plaintext strings.

First step

1. Open the ChatterBox.sln file.

Review the application

1. Select the Chat.cs file in the Solution Explorer. Select the View |
Designer menu command.

Document made for self preparation (Abhishek Maitrey) 100


Enterprise Library for .NET Framework 2.0 Hands On Labs

The Chat form is used for sending and receiving instant messages.
The top TextBox (gray color) displayed the conversation trace. The
bottom TextBox (white color) is used to send new messages.

2. Select the Debug | Start Without Debugging menu command to


run the application.

Two Chat forms will be opened (called Sam and Toby). Messages can
be passed between these forms. Select the Toby window. Type some
text into the Toby Says TextBox, and click the Send button. Repeat
for the Sam window. Note, the conversation appears in both Chat
forms.

Document made for self preparation (Abhishek Maitrey) 101


Enterprise Library for .NET Framework 2.0 Hands On Labs

A Console window is also displayed, to act as a conversation monitor.


Every message is displayed in the Console window.

The messages are being sent between the windows as plaintext. You
will use the Cryptography Block to encrypt and decrypt these
communications using a symmetric key.

3. Close any application window to shutdown the application.

Adding Encryption and Decryption

1. Select the Project | Add Reference … menu command. Select the


Browse tab and select the following assembly located here:

• Microsoft.Practices.EnterpriseLibrary.Security.Cryptography.dll.
2. Select the Chat.cs file in the Solution Explorer. Select the View |
Code menu command.

Document made for self preparation (Abhishek Maitrey) 102


Enterprise Library for .NET Framework 2.0 Hands On Labs

Add the following namespace inclusion to the list of namespaces at the


top of the file:

using Microsoft.Practices.EnterpriseLibrary.Security.Cryptography;

3. Add the following code to the Chat class (added code in bold).

public partial class Chat : Form


{

// TODO: Configuration symmetric algorithm provider name


private const string symmProvider = "ChatProvider";

...

The constant must match a named symmetric crypto provider (see


symmetricCryptoProviders section in the App.config later in the lab).

4. Modify the SendMessage method to encrypt the message using the


Cryptographer (changes in bold).

private void SendMessage(string message)


{
// TODO: Encrypt message
string encrypted =
Cryptographer.EncryptSymmetric(symmProvider, message);

// Fire SendingMessage Event


if (this.SendingMessage != null)
this.SendingMessage(new MessageEventArgs(this._name,
encrypted));
}

5. Modify the MessageReceived method to decrypt the message using


the Cryptographer (changes in bold).

Document made for self preparation (Abhishek Maitrey) 103


Enterprise Library for .NET Framework 2.0 Hands On Labs

private void MessageReceived(MessageEventArgs args)


{
string message = args.Message;

// TODO: Decrypt message


string plainText =
Cryptographer.DecryptSymmetric(symmProvider, message);

this.txtMessages.AppendText(
args.Sender + " says: " + plainText + Environment.NewLine);
}

Enterprise Library Configuration

1. Add a new Application configuration file (App.config) to the


ChatterBox project.

Select the ChatterBox project. Select the Project| Add New


Item… menu command. Select Application configuration file
template. Leave the Name as App.config.

Document made for self preparation (Abhishek Maitrey) 104


Enterprise Library for .NET Framework 2.0 Hands On Labs

2. We will use the Enterprise Library Configuration tool to configure our


application. You may either start this tool from the Windows Start
menu (select All Programs | Microsoft patterns and practices |
Enterprise Library | Enterprise Library Configuration) and open
the App.config file located here.

Alternatively you may configure Visual Studio to open the configuration


file with the tool, as described below.

3. Select the App.config file in the Solution Explorer. Select the View |
Open With… menu command. The OpenWith dialog is displayed.
Click the Add button.

Document made for self preparation (Abhishek Maitrey) 105


Enterprise Library for .NET Framework 2.0 Hands On Labs

4. In the Add Program dialog, set the Program name to the


EntLibConfig.exe file found here. Set the Friendly name to
Enterprise Library Configuration. Click the OK button.

Visual Studio will pass the configuration file (App.config) to the


EntLibConfig.exe program as a command line parameter.

5. In the Open With dialog, select the newly entered Enterprise


Library Configuration program and click the OK button.

Document made for self preparation (Abhishek Maitrey) 106


Enterprise Library for .NET Framework 2.0 Hands On Labs

Configure the application to use Symmetric key Cryptography

1. Right click on the Application and select New


| Cryptography Application Block.

Document made for self preparation (Abhishek Maitrey) 107


Enterprise Library for .NET Framework 2.0 Hands On Labs

2. Select the Cryptography Application Block | Symmetric


Providers node. Select the Action | New | Symmetric Algorithm
Provider menu command.

Document made for self preparation (Abhishek Maitrey) 108


Enterprise Library for .NET Framework 2.0 Hands On Labs

3. The Type Selector dialog (for SymmetricAlgorithm Type) will be


displayed.

Select the RijndaelManaged Type and click the Ok button.

Document made for self preparation (Abhishek Maitrey) 109


Enterprise Library for .NET Framework 2.0 Hands On Labs

An encryption algorithm provides no security if the encryption


algorithm is cracked or is vulnerable to brute force cracking. Custom
algorithms are particularly vulnerable if they have not been tested.
Instead, use published, well-known encryption algorithms that have
withstood years of rigorous attacks and scrutiny.

Recommended key lengths change as computing power grows.


Encryption key lengths that range from 128 bits to 256 bits are
currently considered to be secure. Most modern algorithms use keys
that are at least 128 bits long.

For symmetric algorithms, AES, also known as Rijndael, is


recommended. This algorithm supports key lengths of 128, 192, 256
bits. The DES algorithm is not recommended.

4. The Cryptographic Key Wizard will start. Select the Create a new
key option, and click the Next button.

Document made for self preparation (Abhishek Maitrey) 110


Enterprise Library for .NET Framework 2.0 Hands On Labs

The wizard will lead you through the process of creating and protecting
a cryptographic key.

5. Click the Generate button to generate a new key. Click the Next
button.

Your generated key will no doubt be different to the example shown in


the above picture.

6. Select the Ellipsis (…) button and choose a key file location. For this
lab, the Windows Desktop may prove to be a convenient location.
Select a file name (e.g. ChatterBox.key). Click the Next button.

Document made for self preparation (Abhishek Maitrey) 111


Enterprise Library for .NET Framework 2.0 Hands On Labs

The key is no longer stored in the configuration file. Each key is stored
in a separate file that is protected with DPAPI.

7. Select User mode, or Machine mode, and click the Finish button.

When you create the key, you choose either machine mode or user
mode to limit access to the key.

Document made for self preparation (Abhishek Maitrey) 112


Enterprise Library for .NET Framework 2.0 Hands On Labs

Use machine mode in the following situations:

• Your application runs on its own dedicated server with no other


applications.
• You have multiple applications that run on the same server and
you want those applications to be able to share sensitive
information.

Use user mode if you run your application in a shared hosting


environment and you want to make sure that your application's
sensitive data is not accessible to other applications on the server. In
this situation, each application should run under a separate identity,
and the resources for the application—such as files and databases—
should be restricted to that identity.

Note:

• If you use DPAPI with machine mode, the encrypted string is


specific to a particular computer, so you must generate the
encrypted data on every computer. Do not copy the encrypted
data across computers that are in a server farm or a cluster.
8. Select the Cryptography Application Block | Symmetric
Providers | RijndaelManaged node. Select the following property:

• Name = ChatProvider.

Document made for self preparation (Abhishek Maitrey) 113


Enterprise Library for .NET Framework 2.0 Hands On Labs

ChatProvider is the name of the symmetric provider we used earlier in


the Chat.cs code.

9. Save the application configuration by selecting the File | Save All


menu command.
10. Close the Enterprise Library Configuration tool. Click on Yes in the
dialog box warning about the app.config being modified outside the
source editor.

Run the application

1. Select the Debug | Start Without Debugging menu command.

Pass messages between Toby and Sam. The messages are passed
encrypted (see the encrypted messages in the Console), but decrypted
by the receiver.

Document made for self preparation (Abhishek Maitrey) 114


Enterprise Library for .NET Framework 2.0 Hands On Labs

2. You may or may not have noticed that the application has become a
little less stable now that you are using Cryptographer (hint, try
sending an empty string). you would normally add some code to check
the strings before you try to encrypt or decrypt them. For example you
should check for zero length strings in both the SendMessage and
MessageReceived methods. The MessageReceived method should
also check that the strings you are about to decrypt are a multiple of 4
bytes long and only contain valid Base64 characters. These checks
have been omitted for clarity.
3. Close the application.

Add error handling

1. The best way to handle exceptions is to make sure that they don't
happen in the first place with some guard code. Let's first make sure
that you don't try to encrypt a zero length string.

Document made for self preparation (Abhishek Maitrey) 115


Enterprise Library for .NET Framework 2.0 Hands On Labs

Select the Chat.cs file in the Solution Explorer. Select the View |
Code menu command. Add the following code to the SendMessage
method.

private void SendMessage(string message)


{
if ((message != null) && (message.Trim().Length > 0))

{
// TODO: Encrypt message
string encrypted =
Cryptographer.EncryptSymmetric(symmProvider, message);

// Fire SendingMessage Event


if (this.SendingMessage != null)
this.SendingMessage(new MessageEventArgs(this._name,
encrypted));
}
}

To check the finished solution, open the ChatterBox.sln file.

Exercise 2: Use a HashProvider to store a one-way


hashed password
In this exercise you will use a one-way hashing algorithm to encrypt a
password stored in an XML file.

First step

1. Open the UserUI.sln file.

Review the application

1. Select the Debug | Start Without Debugging menu command to


run the application.
2. The application allows you to manage usernames and passwords in an
XML configuration file.

Document made for self preparation (Abhishek Maitrey) 116


Enterprise Library for .NET Framework 2.0 Hands On Labs

Add a new user named, Elmo. Click the New User button. Enter the
name Elmo, and leave the passwords as the default (P@ssw0rd).
Click the Ok button.

Repeat for new user, Zoe.

3. Click the Save button to save your changes to the UserStore.config


file.
4. Click the Close button to shutdown the application.
5. Select the UserStore.config (in the UserUI project) file in the
Solution Explorer. Select the View | Open menu command.

You can see the password in plain text, not what you would like.

<?xml version="1.0" encoding="utf-8"?>


<configuration>
<configSections>
<section name="userStore"

Document made for self preparation (Abhishek Maitrey) 117


Enterprise Library for .NET Framework 2.0 Hands On Labs

type="UserStore.Configuration.UserSettings, UserStore,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</configSections>
<userStore>
<users>
<add name="Elmo" password="P@ssw0rd" />
<add name="Zoe" password="P@ssw0rd" />
</users>
</userStore>
</configuration>

It is not necessarily a good idea to encrypt passwords using a


symmetric key like the one you used in the previous exercise because
if the key is compromised, so are all our passwords.

One-way hashing algorithms are usually used with passwords. You


would hash the password before comparing it with a hashed password
stored somewhere (usually in a database). This way even if the
database is compromised our passwords are still safe.

Adding extra information 'Salt' to the password before hashing also


makes the password much harder to crack. This is the default with the
Cryptography Block's hashing providers.

Configure the Hash Provider

1. Select the App.config (in the UserUI project) in the Solution


Explorer. Select the View | Open With… menu command. Select
Enterprise Library Configuration and click the OK button.
2. The application configuration already has two Configuration Sources
defined. The application is using the Enterprise Library wrapper
classes for Configuration to manage the UserStore.config location
and contents.

Document made for self preparation (Abhishek Maitrey) 118


Enterprise Library for .NET Framework 2.0 Hands On Labs

3. Right click on the application configuration file and select the New |
Cryptography Application Block menu command.

Document made for self preparation (Abhishek Maitrey) 119


Enterprise Library for .NET Framework 2.0 Hands On Labs

4. Select the Cryptography Application Block | Hash Providers


node. Select the Action | New | HashAlgorithm Provider menu
command.

Document made for self preparation (Abhishek Maitrey) 120


Enterprise Library for .NET Framework 2.0 Hands On Labs

5. The Type Selector dialog (for HashAlgorithm Type) will be displayed.

Select the SHA1Managed Type and click the Ok button.

Document made for self preparation (Abhishek Maitrey) 121


Enterprise Library for .NET Framework 2.0 Hands On Labs

For hashing algorithms, the SHA256Managed algorithm is


recommended. This algorithm uses a hash size of 256 bits. The hash
size of SHA1Managed hashing algorithm is 160 bits. This algorithm is
acceptable but not encouraged. The MD4 and MD5 algorithms are no
longer recommended.

6. Select the Cryptography Application Block | Hash Providers |


SHA1Managed node. Select the following property:

• Name = PasswordHasher, and


• SaltEnabled = True.

Document made for self preparation (Abhishek Maitrey) 122


Enterprise Library for .NET Framework 2.0 Hands On Labs

7. Select the File | Save All menu command to save the application
configuration. Close the Enterprise Library Configuration Console.

Use Hash Provider

1. Select the UserStore project in the Solution Explorer. Select the Project | Add
Reference … menu command. Select the Browse tab and select the following
assembly located here:

• Microsoft.Practices.EnterpriseLibrary.Security.Cryptography.dll.
2. Select the Security | HashHelper.cs file (in the UserStore project)
in the Solution Explorer. Select the View | Code menu command.

Add the following namespace inclusion:

using Microsoft.Practices.EnterpriseLibrary.Security.Cryptography;

Document made for self preparation (Abhishek Maitrey) 123


Enterprise Library for .NET Framework 2.0 Hands On Labs

3. Add the following code to the HashHelper class.

class HashHelper
{
private HashHelper() { }

// TODO: Hash provider name must match app.config


private const string hashProvider = "PasswordHasher";

...

The constant must match a named Hash provider (see hashProviders


section in the App.config file).

4. Modify the following code in the CreateHash method.

public static string CreateHash(string plainText)


{
string hash = null;

// TODO: Hash the plain text


hash = Cryptographer.CreateHash(hashProvider, plainText);

return hash;
}

Keep in mind that sensitive data should be cleared in memory as soon


as possible. Leaving sensitive data unencrypted in memory can expose
the data to security risks. You should note that data in memory may
also end up on the hard disk, because the operating system can write
data to a swap file. Also, if the computer crashes, the operating
system can dump the contents of memory to disk.

Document made for self preparation (Abhishek Maitrey) 124


Enterprise Library for .NET Framework 2.0 Hands On Labs

5. Select the Debug | Start Without Debugging menu command to


run the application.
6. Reset the password for Elmo. Click the Reset Password button.
Leave the passwords as the default (P@ssw0rd). Click the Ok button.

Repeat for new user, Zoe.

You must replace the existing plain text password in the


UserStore.config file with a password hash.

7. Click the Save button to save your changes to the UserStore.config


file.
8. Attempt to change Elmo's password, which will validate the existing
password. Click the Change Password button. The Old Password is
P@ssw0rd (the default). Use any new password you like (not zero
length) and click the Ok button.

Document made for self preparation (Abhishek Maitrey) 125


Enterprise Library for .NET Framework 2.0 Hands On Labs

Why does the validation of the existing password fail? Explanation


later.

9. Click the Close button to shutdown the application.


10. Select the UserStore.config (in the UserUI project) file in the
Solution Explorer. Select the View | Open menu command.

You can see the password has been hashed.

Notice the hashing is different in each case, even though the actual
password is the same. The difference is due to the addition of the
'Salt'. Hence, to test the validity of a password we cannot simply
reapply the hashing to the plain text password and string compare to
two hashed values. This is why the Change Password failed earlier.

11. Select the Security | HashHelper.cs file (in the UserStore project)
in the Solution Explorer. Select the View | Code menu command.

Modify the following code in the CompareHash method.

public static bool CompareHash(string plainText, string hashedText)


{
bool compare = false;

// TODO: Compare plain text with hash


compare = Cryptographer.CompareHash(hashProvider,
plainText, hashedText);

return compare;
}

12. Select the Debug | Start Without Debugging menu command to


run the application.
13. Change Elmo's password, which will validate the existing password.
Click the Change Password button. The Old Password is P@ssw0rd

Document made for self preparation (Abhishek Maitrey) 126


Enterprise Library for .NET Framework 2.0 Hands On Labs

(the default). Use any new password you like (not zero length) and
click the Ok button.

The password is changed successfully.

More information

1. For an example of using the cryptography block to encrypting security


cookies for use with WS-Security Secure Conversation, see the "Using
Advanced Microsoft® .NET Application Security Techniques" course
which is part of the Mastering Industrial Strength .NET series.

To check the finished solution, open the UserUI.sln file.

Copyright © 2005 Microsoft. All Rights Reserved.

Document made for self preparation (Abhishek Maitrey) 127


Enterprise Library for .NET Framework 2.0 Hands On Labs

Enterprise Library Hands On Labs


Lab 6: Security Application Block - Hands
On Lab
After completing this lab, you will be able to:

• To use ASP.NET Membership for application authentication and


authorization.
• To use the Enterprise Library Security block to add rule-based
authorization.

Scenario
This lab demonstrates the use of the Enterprise Library, Security Application
Block.

Estimated Time To Complete this lab: 30 minutes.

Exercise 1: Secure an Application


In this exercise you will add authentication and role based authorization to
an existing application. You will configure application users and roles via the
ASP.NET Membership API.

First step

1. Open the BugSmak.sln file.

Adding authentication to the application

1. Select the Debug | Start Without Debugging menu command to


run the application. The application as yet is unable to authenticate
users.

Document made for self preparation (Abhishek Maitrey) 128


Enterprise Library for .NET Framework 2.0 Hands On Labs

The application will be configured to use the ASP.NET Membership API


for authentication (login security).

2. Close the application.


3. Select the Security \ SecurityHelper.cs file in the Solution Explorer.
Select the View | Code menu command.

Add the following namespace inclusion to the list of namespaces at the


top of the file:

using System.Web.Security;

4. Add the following code to the Authenticate method.

public static bool Authenticate(string username, string password)


{
bool authenticated = false;

// TODO: Authenticate Credentials


authenticated = Membership.ValidateUser(username,
password);

// TODO: Get Roles

return authenticated;
}

The Authenticate method is called by the LoginForm to validate the


user credentials. The Membership.ValidateUser method is called to
perform the validation.

The membership system uses a provider model so that the application


is not tied to a particular data store. ASP.NET ships with two

Document made for self preparation (Abhishek Maitrey) 129


Enterprise Library for .NET Framework 2.0 Hands On Labs

membership providers: one that uses Microsoft SQL Server as a data


source and another that uses Windows Active Directory.

It is also possible to create a custom membership provider, which we


have done to read the application members from an XML file.

5. Select the Security | Providers |


ReadOnlyXmlMembershipProvider.cs file in the Solution Explorer.
Select the View | Code menu command and review the code.

The ReadOnlyXmlMembershipProvider (inherits from


MembershipProvider) is an example of a custom membership provider.
This implementation, which reads an unencrypted XML file is
not meant as an example of good practice, but useful for this
laboratory exercise.

6. Select the App.config file in the Solution Explorer. Select the View |
Open menu command.

Review the membership provider configuration. The authentication


data store is identified as the Users.xml file.

<?xml version="1.0" encoding="utf-8"?>


<configuration>
<system.web>
<membership
defaultProvider="ReadOnlyXmlMembershipProvider">
<providers>
<add name="ReadOnlyXmlMembershipProvider"

type="BugSmak.Security.Providers.ReadOnlyXmlMembershipPr
ovider, BugSmak"
description="Read-only XML membership provider"
xmlFileName="Users.xml" />
</providers>
</membership>
...

</system.web>
</configuration>

Document made for self preparation (Abhishek Maitrey) 130


Enterprise Library for .NET Framework 2.0 Hands On Labs

Once you have a custom membership provider, you can configure your
application to use that provider in the same way that you configure the
application to use an ASP.NET provider. The Membership class will
automatically invoke your custom provider to communicate with your
authentication data source.

7. Select the Users.xml file in the Solution Explorer. Select the View |
Open menu command.

The following users have been pre-defined.

Username Password Role(s)


Tom P@ssw0rd Employee
Dick P@ssw0rd Developer
Harry P@ssw0rd Manager

8. Select the Debug | Start Without Debugging menu command to


run the application.

Sign-in as Tom, Dick or Harry to confirm the correct setup of the


membership provider.

Select the File | Sign Out menu command and attempt to sign in with
an incorrect username or password.

Document made for self preparation (Abhishek Maitrey) 131


Enterprise Library for .NET Framework 2.0 Hands On Labs

The Password field has been initialized to P@ssw0rd (see


LoginForm.cs) to save you repeatedly typing the password during the
laboratory exercise.

Notes:

• The application is the skeleton of a simple bug tracking system.


The application has a skeleton for the following functions: Raise
a Bug, Assign a Bug to a developer for resolution, and Resolve a
Bug.
• The password is case sensitive, but the username is not.
9. Sign-in as Tom. Select the Tasks | Raise New Bug menu
command. You are confronted with a message "Sorry, you aren't
allowed to access that form". Similarly, attempt to open the other
tasks (Assign Bug, and Resolve Bug).
10.Close the application.

Adding role-base authorization

1. Select the TaskForms \ RaiseBug.cs file in the Solution Explorer.


Select the View | Code menu command.

Review the PrincipalPermissions.

The RaiseBug form demands that the user have any of the Developer,
Employee, or Manager roles. Attempting to run the form without the
necessary authorization results in a SecurityException which is
caught by the MainForm (see MainForm.cs).

The following role requirements are enforced via PrincipalPermissions:

TaskForm Role Required


RaiseBug Employee, Developer, or Manager
AssignBug Manager
ResolveBug Developer or Manager

Document made for self preparation (Abhishek Maitrey) 132


Enterprise Library for .NET Framework 2.0 Hands On Labs

We have implemented authentication, but have not determined the


user roles. The application will be configured to use a membership
RoleProvider to retrieve user roles later in this section of the lab.

2. Select the Security \ SecurityHelper.cs file in the Solution Explorer.


Select the View | Code menu command.

Add the following code to the Authenticate method.

public static bool Authenticate(string username, string password)


{
bool authenticated = false;

// TODO: Authenticate Credentials


authenticated = Membership.ValidateUser(username, password);

// TODO: Get Roles


if (!authenticated)
return false;

IIdentity identity;
identity = new GenericIdentity(username,
Membership.Provider.Name);

string[] roles = Roles.GetRolesForUser(identity.Name);


IPrincipal principal = new GenericPrincipal(identity, roles);

// Place user's principal on the thread


Thread.CurrentPrincipal = principal;

Document made for self preparation (Abhishek Maitrey) 133


Enterprise Library for .NET Framework 2.0 Hands On Labs

return authenticated;
}

The roles are retrieved from the Users.xml file via a custom
RoleProvider (ReadOnlyXmlRoleProvider.cs), and a new principal
created which contains the users identity and roles.

To use the authenticated principal in our application we place it on the


Thread.

3. Select the App.config file in the Solution Explorer. Select the View |
Open menu command.

Review the role manager provider configuration. The data store is


identified as the Users.xml file.

<?xml version="1.0" encoding="utf-8"?>


<configuration>
<system.web>
...

<roleManager enabled="true"
defaultProvider="ReadOnlyXmlRoleProvider">
<providers>
<add name="ReadOnlyXmlRoleProvider"

type="BugSmak.Security.Providers.ReadOnlyXmlRoleProvider,
BugSmak"
description="Read-only XML role provider"
xmlFileName="Users.xml" />
</providers>
</roleManager>
</system.web>
</configuration>

4. Select the Debug | Start Without Debugging menu command to


run the application.

Document made for self preparation (Abhishek Maitrey) 134


Enterprise Library for .NET Framework 2.0 Hands On Labs

Sign-in as Tom, Dick and Harry in turn to confirm the correct setup
of the role provider.

User Task Access


Tom (Employee) Raise New Bug
Raise New Bug, and
Dick (Developer)
Resolve Bug
Raise New Bug,
Harry (Manager) Resolve Bug, and
Assign Bug.

To check the finished solution, open the BugSmak.sln file.

Exercise 2: Use Rule-based Authorization In an


Application
In this exercise you will use an AuthorizationProvider to secure application
tasks.

In the previous exercise you secured an application using role based


authorization. Role based authorization can be difficult to configure as roles
do not always neatly map to tasks or use cases.

You will use the AuthorizationProvider to:

• map task based authorization to complex combinations of roles, and


• extract authorization from the application code.

First step

1. Open the BugSmak.sln file.

Enterprise Library Configuration

1. We will use the Enterprise Library Configuration tool to configure our


application. You may either start this tool from the Windows Start
menu (select All Programs | Microsoft patterns and practices |

Document made for self preparation (Abhishek Maitrey) 135


Enterprise Library for .NET Framework 2.0 Hands On Labs

Enterprise Library | Enterprise Library Configuration) and open


the App.config file located here.

Alternatively you may configure Visual Studio to open the configuration


file with the tool, as described below.

2. Select the App.config file in the Solution Explorer. Select the View |
Open With… menu command. The OpenWith dialog is displayed.
Click the Add button.

3. In the Add Program dialog, set the Program name to the


EntLibConfig.exe file found here. Set the Friendly name to
Enterprise Library Configuration. Click the OK button.

Document made for self preparation (Abhishek Maitrey) 136


Enterprise Library for .NET Framework 2.0 Hands On Labs

Visual Studio will pass the configuration file (App.config) to the


EntLibConfig.exe program as a command line parameter.

4. In the Open With dialog, select the newly entered Enterprise


Library Configuration program and click the OK button.

Adding Authorization Rules with the Enterprise Library Configuration Tool

Document made for self preparation (Abhishek Maitrey) 137


Enterprise Library for .NET Framework 2.0 Hands On Labs

1. Right click on the Application and select New | Security Application


Block.

2. Add a new Authorization Rule Provider. Select the Security


Application Block | Authorization node. Select the Action | New
| Authorization Rule Provider menu command.

Document made for self preparation (Abhishek Maitrey) 138


Enterprise Library for .NET Framework 2.0 Hands On Labs

3. Set the following property:

• Name = BugSmak Rules.

Document made for self preparation (Abhishek Maitrey) 139


Enterprise Library for .NET Framework 2.0 Hands On Labs

4. Select the Security Application Block | Authorization | BugSmak


Rules node. Select the Action | New | Rule menu command.

Document made for self preparation (Abhishek Maitrey) 140


Enterprise Library for .NET Framework 2.0 Hands On Labs

5. Open the Rule Expression Editor by clicking the ellipsis in the


Expression property.

6. Set the following properties:

• Rule Name = Raise Bug, and


• Expression = R:Developer OR R:Employee OR R:Manager.

Click the OK button.

Document made for self preparation (Abhishek Maitrey) 141


Enterprise Library for .NET Framework 2.0 Hands On Labs

The user must be in either Developer, Employee, or Manager role.

7. Add the following New Rules and Expressions:

Rule Name Expression


Raise Bug ** R:Developer OR R:Employee OR R:Manager
Assign Bug R:Manager
Resolve Bug R:Developer OR R:Manager

** Already entered in previous step.

Document made for self preparation (Abhishek Maitrey) 142


Enterprise Library for .NET Framework 2.0 Hands On Labs

8. Select the Security Application Block node and set the following
property:

• DefaultAuthorizationInstance = BugSmak Rules.

Document made for self preparation (Abhishek Maitrey) 143


Enterprise Library for .NET Framework 2.0 Hands On Labs

9. Select the File | Save All menu command to save the configuration.
Close the Enterprise Library Configuration tool.

Adding Task Based Authorization

1. Select the TaskForms \ RaiseBug.cs file in the Solution Explorer.


Select the View | Code menu command.

The form no longer uses the hard-coded PrincipalPermissions


(commented-out). Rather the more flexible task authorization is
checked before the object is constructed.

AssignBug.cs and ResolveBug.cs have similar code.

//[PrincipalPermission(SecurityAction.Demand, Role = "Employee")]


//[PrincipalPermission(SecurityAction.Demand, Role = "Developer")]
//[PrincipalPermission(SecurityAction.Demand, Role = "Manager")]

Document made for self preparation (Abhishek Maitrey) 144


Enterprise Library for .NET Framework 2.0 Hands On Labs

public static RaiseBug Create()


{
// TODO: Check Authorization
if (!SecurityHelper.Authorized(AuthRule.Raise))
{
throw new SecurityException();
}

return new RaiseBug();


}

Notes:

•For compile-time checking, the rule names (e.g. "Raise Bug") are
mapped to constants in the Constants.cs file.
2. Select the Project | Add Reference … menu command. Select the
Browse tab and select the following assembly located here.

•Microsoft.Practices.EnterpriseLibrary.Security.dll.
3. Select the Security \ SecurityHelper.cs file in the Solution Explorer.
Select the View | Code menu command.

Add the following namespace inclusion to the list of namespaces at the


top of the file:

using Microsoft.Practices.EnterpriseLibrary.Security;

4. Add the following code to Authorized method.

public static bool Authorized(string rule)


{
bool authorized = false;

// TODO: Check rule-base authorization


IAuthorizationProvider ruleProvider;

Document made for self preparation (Abhishek Maitrey) 145


Enterprise Library for .NET Framework 2.0 Hands On Labs

ruleProvider =
AuthorizationFactory.GetAuthorizationProvider();

authorized =
ruleProvider.Authorize(Thread.CurrentPrincipal, rule);

return authorized;
}

Use the AuthorizationFactory to retrieve the default authorization


provider. The authorization provider will test the current principal
(roles and identity) against the rule.

5. Select the Debug | Start Without Debugging menu command to


run the application.

Sign-in as Tom, Dick and Harry in turn to confirm the correct setup
of the role provider.

User Task Access


Tom (Employee) Raise New Bug
Raise New Bug, and
Dick (Developer)
Resolve Bug
Raise New Bug,
Harry (Manager) Resolve Bug, and
Assign Bug.

6. Close the application.

More information

1. For more information on how to implement security in distributed


applications, see the "Using Advanced Microsoft® .NET Application
Security Techniques" course as part of the Mastering Industrial

Document made for self preparation (Abhishek Maitrey) 146


Enterprise Library for .NET Framework 2.0 Hands On Labs

Strength .NET series. This uses Enterprise Library to incorporate


security in distributed solutions, including building your own security
providers and integrating with external authorization systems (e.g.
authorization manager).

To check the finished solution, open the BugSmak.sln file.

Copyright © 2005 Microsoft. All Rights Reserved.

Document made for self preparation (Abhishek Maitrey) 147

You might also like