I have a SQL Server 2008 database with two tables, a .NET 4.5 application using a TransactionScope
with two queries to the database, each using their own separate connection which shares a single connection string.
This code that works fine:
internal static void Main(string[] args)
{
string connStr = string.Format(
"Data Source={0};Initial Catalog={1};" +
"Integrated Security=True", "My DB Server", "My Database");
using (var scope = new TransactionScope())
{
string query1 = "(actual query not relevant)";
var ds = GetSqlServerDataSet(query1, connStr);
string query2 = "(actual query not relevant)";
var ds1 = GetSqlServerDataSet(query2, connStr);
scope.Complete();
}
}
private static System.Data.DataSet GetSqlServerDataSet(string usingQuery,
string usingConnectionString,
params System.Data.SqlClient.SqlParameter[] withParameters)
{
using (var ds = new System.Data.DataSet())
using (var conn = new System.Data.SqlClient.SqlConnection(usingConnectionString))
using (var command = new System.Data.SqlClient.SqlCommand(usingQuery, conn))
{
command.Parameters.AddRange(withParameters);
using (var adapter = new System.Data.SqlClient.SqlDataAdapter(command))
{
adapter.Fill(ds);
}
return ds;
}
}
Now, if I throw an exception inside the scope to test roll-back, that's when stuff gets strange. I'm using a referenced class library I've written to persist info about exceptions to a database. It's the same type of setup -- same SQL Server, .NET version, identical ADO.NET code, etc. It's just writing to a different database.
Here's how it works: I've added this method to my app:
private static void HandleUnhandledException(Object sender, System.UnhandledExceptionEventArgs e)
{
ExceptionHandling.Core.Main.ProcessException((Exception) e.ExceptionObject);
Environment.Exit(0);
}
and I've added this line to the top of my Main
method:
AppDomain.CurrentDomain.UnhandledException += HandleUnhandledException;
Now when I throw an exception, e.g. throw new Exception("blah");
at the bottom of Main
right before scope.Complete()
, it automatically jumps to HandleUnhandledException
, and the rest happens as I've described above. This results in System.Transactions.TransactionManagerCommunicationException
with message:
Network access for Distributed Transaction Manager (MSDTC) has been disabled. Please enable DTC for network access in the security configuration for MSDTC using the Component Services Administrative tool.
This happens on the call to Connection.Open()
in my class library.
So what's happening here? I know what the error is telling me, and I know how to fix it. My question is why is this happening in the first place? I thought the using
statement would take care of rolling back the transaction before it hits my HandleUnhandledException
method, so there shouldn't be two transactions involved here. Or am I wrong?