4

我有一個帶有兩個表的SQL Server 2008數據庫,一個使用TransactionScope的.NET 4.5應用程序,其中有兩個查詢到數據庫,每個使用它們自己的單獨連接一個單個連接字符串。MSDTC事務被提升爲在事務處理範圍之外執行的查詢上分佈式

此代碼工作正常:

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; 
    } 
} 

現在,如果我扔範圍測試回滾內一個例外,那就是當東西變得陌生。我正在使用我編寫的引用類庫來持久化關於數據庫異常的信息。這是相同類型的設置 - 相同的SQL Server,.NET版本,相同的ADO.NET代碼等。它只是寫入不同的數據庫。

下面是它如何工作的:我已經添加了這個方法我的應用程序:

private static void HandleUnhandledException(Object sender, System.UnhandledExceptionEventArgs e) 
{ 
    ExceptionHandling.Core.Main.ProcessException((Exception) e.ExceptionObject); 
    Environment.Exit(0); 
} 

,我已經加入這一行我Main方法的頂部:

AppDomain.CurrentDomain.UnhandledException += HandleUnhandledException; 

現在,當我拋出一個例外,例如throw new Exception("blah");Main的底部,就在scope.Complete()之前,它會自動跳轉到HandleUnhandledException,剩下的就像我上面描述的那樣。這導致System.Transactions.TransactionManagerCommunicationException與消息:爲分佈式事務管理器(MSDTC)

網絡訪問已被禁用 。請使用組件服務管理 工具爲MSDTC配置安全 配置中的DTC以啓用網絡訪問。

這發生在我的課程庫中致電Connection.Open()

那麼這裏發生了什麼?我知道錯誤告訴了我什麼,我知道how to fix it。我的問題是這是爲什麼發生在第一位?我認爲using聲明會在處理我的HandleUnhandledException方法之前處理回滾事務,因此這裏不應涉及兩個事務。或者我錯了?

+0

你確定引用的類庫本身不需要MSDTC嗎? –

+0

絕對。我一直在用我的項目十年。 –

+0

它是什麼類型的應用程序?控制檯,WPF,Webb? –

回答

4

發生這種情況的原因是,當您的HandleUnhandledException方法運行時 - 您仍在using區塊內且它的finally部分尚未運行。這很容易驗證與此代碼:

class Program { 
    static void Main(string[] args) { 
     AppDomain.CurrentDomain.UnhandledException += OnUnhandledException; 
     try { 
      throw new Exception("test"); 
     } 
     finally { 
      Console.WriteLine("finally"); 
     } 
    } 

    private static void OnUnhandledException(object sender, UnhandledExceptionEventArgs e) { 
     Console.WriteLine("handle exception"); 
    } 
} 

,輸出:

handle exception 
Unhandled exception: System.Exception: test ... 
finally 

您可能需要閱讀(例如和意見,由埃裏克·理柏)this問題對相關行爲的討論。但我認爲理由與您的問題不太相關 - 我們可以說它就是這樣。

鑑於這些信息,很明顯你爲什麼會觀察到你的異常 - 你仍然處於未被接受的事務範圍內,並嘗試打開連接到不同的數據庫。附帶你的情況我想起

一種解決方案是檢查,如果我們發現內幕交易,抑制它,如果是(因爲反正你不希望你的日誌代碼以任何方式影響環境事務):

private static void HandleException(Exception ex) { 
    TransactionScope scope = null; 
    if (Transaction.Current != null) 
     scope = new TransactionScope(TransactionScopeOption.Suppress); 
    try { 
     // do stuff 
    } 
    finally { 
     scope?.Dispose(); 
    } 
} 

或者,也許只是總是在壓制TransactionScope內運行。

+0

太棒了!非常感謝。 –

+0

@ rory.ap還有一件事我忘了提及。我看到你在異常處理程序中使用'Environment.Exit'。有了這個,最後塊將不會運行(容易看到與我的答案相同的例子)。不知道在這種情況下有多危險,但有些事情要注意我的想法。此外,進程不會崩潰,因爲控制權不會到達默認的未處理異常處理程序。 – Evk

相關問題