我正在将TransactionBlock
代码用于在连接字符串中存储连接字符串的Web应用程序。
到目前为止,我只需要写入本地数据库,因此,此代码有效。但是,我现在需要另一种数据访问方法,使用不同的连接字符串写入另一个数据库。
我在配置文件中创建了一个新的连接字符串,但我不确定如何调用它并将其交换出来。
到目前为止我的骨架代码是:
public class TransactionBlock : IDisposable
{
private readonly bool _mFirstTransactionBlock = false;
private bool _mDisposed = false;
public TransactionBlock(string connectionStringConfigKey = null)
{
if (connectionStringConfigKey != null && CurrentTransaction != null)
throw new Exception("Can't create a new transactionBlock with a specific connectionstring if you are already within a block.");
// Open a connection if we haven't yet already
if (CurrentTransaction == null) // we don't have a transaction yet so create one:
{
SqlConnection conn = new SqlConnection(ConnectionString); // Create a new connection object for the connection string.
try
{
conn.Open();
}
catch (SqlException ex)
{
// Severity 20 errors are returned when there are connection
// problems, so we only retry if the severity is 20.
// Don't worry about deadlock errors in here - we're just connecting
// to the database, not running anything which could be deadlocked.
if (ex.Class != 20) throw;
// Clear connection pool of all connections related to the given connection string.
SqlConnection.ClearPool(conn);
// Try to open the connection once again, catching any error.
try { conn.Open(); }
catch { conn = null; }
// If 2nd attempt failed, throw original exception.
if (conn == null) throw;
}
CurrentTransaction = conn.BeginTransaction();
_mFirstTransactionBlock = true;
}
}
public void Commit()
{
if (_mFirstTransactionBlock)
{
Dispose(true);
}
}
public void Dispose()
{
if (_mFirstTransactionBlock)
{
Dispose(false);
}
}
private void Dispose(bool commit)
{
if (_mDisposed)
return; // committed and cleaned up already.
try
{
var transaction = CurrentTransaction;
var connection = transaction.Connection; // taking a reference to the connection object as rollback will set it to null;
if (commit)
{
transaction.Commit();
}
else // rollback the transaction if it hasn't been commited.
{
transaction.Rollback();
}
if (connection != null)
{
connection.Close();
connection.Dispose();
}
transaction.Dispose();
}
finally // ensure that regardless of connection exceptions, the state is set to disposed.
{
// remove current transaction from context.
CurrentTransaction = null;
_mDisposed = true;
}
}
private static SqlTransaction CurrentTransaction
{
get
{
return CurrentContext.GetItem<SqlTransaction>("__Transaction");
}
set
{
CurrentContext.SetItem("__Transaction", value);
}
}
public static SqlConnection Connection
{
get { return CurrentTransaction.Connection; }
}
public static SqlTransaction Transaction
{
get { return CurrentTransaction; }
}
private static string connectionString;
public static string ConnectionString
{
get
{
if (string.IsNullOrEmpty(connectionString))
{
try
{
connectionString = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString ?? "";
}
catch (Exception ex)
{
ServiceLogger.LogError("Database: Creating SQL Connection. Can not find connection string. Nothing will work until this is resolved.");
throw;
}
if (string.IsNullOrEmpty(connectionString))
ServiceLogger.LogError("Database: Creating SQL Connection. Can not find connection string. Nothing will work until this is resolved.");
else
ServiceLogger.LogInfo(String.Format("Database: Creating SQL Connection. Connection string: {0}", connectionString));
}
return connectionString;
}
}
#region CurrentContext Helper class
/// <summary>
/// Helper class for easy access to the appropriate context containers.
/// </summary>
private static class CurrentContext
{
public static T GetItem<T>(string key) where T : class
{
if (HttpContext.Current != null)
{
return (T)HttpContext.Current.Items[key];
}
else
{
return (T)CallContext.GetData(key);
}
}
public static void SetItem(string key, object value)
{
if (HttpContext.Current != null)
{
HttpContext.Current.Items[key] = value;
}
else
{
CallContext.SetData(key, value);
}
}
}
#endregion
/// <summary>
/// Adds the application name to the connection string, but only if it is missing.
/// </summary>
/// <param name="connectionString"></param>
/// <returns>Modified connection string</returns>
private static string AddApplicationNameIfMissing(string connectionString)
{
if (connectionString == null)
return null;
// If the connection string hasn't already been configured with an application name,
// then add one (assumes the application name is not 1st element, as unlikely to have a leading ';').
if (connectionString.IndexOf(";Application Name=", StringComparison.OrdinalIgnoreCase) >= 0)
return connectionString;
// TODO: if this turns out to be too slow to perform on each query then caching connection strings should be added.
// take site name if run from a website or webservice otherwise take process path.
string appName = System.Web.Hosting.HostingEnvironment.SiteName ?? Path.GetFileNameWithoutExtension(Environment.GetCommandLineArgs()[0]);
return connectionString += string.Format("{0}Application Name={1}", connectionString.EndsWith(";") ? "" : ";", appName);
}
private interface IStructuredParam
{
DataTable ToDataTable();
}
public SqlCommand CreateSpCommand(string sql)
{
if (string.IsNullOrWhiteSpace(sql)) throw new ArgumentNullException("sql");
SqlTransaction tran = CurrentTransaction;
if (tran == null) throw new NullReferenceException("CurrentTransaction");
SqlConnection conn = tran.Connection;
if (conn == null) throw new NullReferenceException("Connection");
SqlCommand cmd = conn.CreateCommand();
if (cmd == null) throw new NullReferenceException("Command");
cmd.CommandText = sql;
cmd.CommandType = CommandType.StoredProcedure;
cmd.Transaction = tran;
return cmd;
}
public void AddParameter(SqlCommand cmd, string name, SqlDbType type, int size, object value, bool isOutput)
{
var p = cmd.CreateParameter();
p.ParameterName = name;
p.SqlDbType = type;
p.Size = size;
if (value == null)
p.Value = DBNull.Value;
else if (type == SqlDbType.Structured)
p.Value = ((IStructuredParam)value).ToDataTable();
else
p.Value = value;
p.Direction = isOutput == false ? ParameterDirection.Input : ParameterDirection.Output;
cmd.Parameters.Add(p);
}
public void ExecuteAndMapReader(SqlCommand command, params Action<IDataReader>[] mappingMethods)
{
using (var reader = command.ExecuteReader())
{
int i = 0;
do
{
while (reader.Read())
{
if (reader.HasRows && mappingMethods != null && mappingMethods.Any())
mappingMethods[i](reader);
}
i++;
} while (reader.NextResult());
reader.Close();
}
}
}