1) Web.config settings

Register the HTTP Handler: The handler is used to start and end sessions and also provides a very simple administrative UI.
IIS 6 and earlier
	<system.web>
		<httpHandlers>
			<add verb="*" path="Amnesia.axd" validate="false" type="Amnesia.Handler, Amnesia" />


IIS 7+
	<system.webServer>
		<handlers>
			<add name="Amnesia" verb="*" path="Amnesia.axd" type="Amnesia.Handler, Amnesia" />



Disabling on Production Systems

Although the handler is fairly lightweight, its recommended that Amnesia be disabled on production systems by unregistering the handler for security reasons. Just remove the registration from the web.config to disable Amnesia.

2) Application Changes

Amnesia relies on .NET ambient transactions (System.Transactions and TransactionScope) to transact all actions. If your application already uses this technique then very little work is required to use Amnesia.

TransactionScope (System.Transactions)

Amnesia relies on the TransactionScope class and the Distributed Transaction Coordinator (MSDTC) in order to handle distributed transaction management. If you are working with a newer application chances are good you are using this class. If you aren't then there are many resources on the web that describe how to use the TransactionScope.

Note: Although Amnesia requires MSDTC, distributed transactions are only used if an Amnesia session is active. In other words, when there is no Amnesia session, then the application under test should behave "normally".

Connection Sharing Across Threads

Connections that are part of Amnesia's distributed transaction must be shared across requests, otherwise the database connection pool will grow rapidly. This can be accomplished by storing connections in a static Dictionary based on their Distributed Transaction ID.

Amnesia includes the Amnesia.Data.ConnectionHelper class to assist with connection management.

Code before Amnesia integration:

IDbConnection connection = AppCodeToCreateConnection(connStr);

Code after Amnesia integration:

using Amnesia.Data;
.
.
.
IDbConnection connection = ConnectionHelper.GetAmbientConnection(connStr, AppCodeToGetConnection) ?? AppCodeToGetConnection(connStr);


Also, you will need to synchronize access to the shared connections before using them.

Command execution before Amnesia

IDbCommand command;
.
.
.
using(IDataReader result = command.ExecuteReader())
{
}

Command execution after Amnesia

using Amnesia.Data;
.
.
.
IDbCommand command;
.
.
.
// Synchronize access to the connection. No locking is performed if there is no Amnesia session
using(ConnectionHelper.LockConnection(command.Connection))
using(IDataReader result = command.ExecuteReader())
{
}

Command execution after Amnesia, with nested queries

using Amnesia.Data;
.
.
.
IDbCommand command;
.
.
.
// Synchronize access to the connection. No locking is performed if there is no Amnesia session
using(ConnectionHelper.LockConnection(command.Connection))
using(IDataReader result = ConnectionHelper.PrepareReader(command.ExecuteReader()))
{
    // if another query needs to be execute, its OK due to the use of a disconnected reader
    // which will read the results of the entire reader prior to closing   
}

Last edited Nov 23, 2010 at 2:10 PM by matthooper, version 16

Comments

No comments yet.