4

두 테이블이있는 SQL Server 2008 데이터베이스, 데이터베이스에 대한 쿼리가 두 개있는 TransactionScope을 사용하는 .NET 4.5 응용 프로그램, 각각은 자신의 별도 연결을 사용합니다 a 연결 문자열. 잘 작동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합니다. throw new Exception("blah");Main의 바로 전에 scope.Complete() 앞에 자동으로 HandleUnhandledException으로 점프하고 나머지는 위에서 설명한대로 발생합니다. 이 메시지와 함께 System.Transactions.TransactionManagerCommunicationException 결과 : 분산 트랜잭션 관리자 (MSDTC)에 대한

네트워크 액세스 사용할 수 없습니다. 구성 요소 서비스 관리 도구를 사용하여 MSDTC의 보안 구성에서 네트워크 액세스를 위해 DTC를 사용하도록 설정하십시오.

내 클래스 라이브러리에서 Connection.Open()을 호출 할 때 발생합니다.

그래서 여기서 어떻게됩니까? 오류가 무엇을 말하고 있는지 알고 있으며, 나는 how to fix it을 알고 있습니다. 제 질문은 입니다. 왜 이런 일이 처음 발생합니까?? 내 HandleUnhandledException 메서드를 실행하기 전에 using 문이 트랜잭션 롤백을 처리 할 것이라고 생각 했으므로 여기서는 두 가지 트랜잭션이 있어서는 안됩니다. 아니면 내가 틀렸어?

+0

참조 된 클래스 라이브러리가 MSDTC 만 필요로하는 것은 확실합니까? –

+0

물론입니다. 저는 10 년 동안이 프로젝트를 사용하고 있습니다. –

+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

Brilliant! 고마워. –

+0

@ rory.ap 내가 언급 한 것을 잊어 버린 또 하나의 일. 예외 처리기에서'Environment.Exit'을 사용하는 것을 보았습니다. 이것으로 finally 블록이 전혀 실행되지 않습니다 (내 대답과 같은 예제로보기 쉽습니다). 이 경우 얼마나 위험한 지 확신 할 수 없지만 제 생각에는 그 사실을 알고 있어야합니다. 또한 컨트롤이 처리되지 않은 기본 예외 처리기에 도달하지 않기 때문에 프로세스가 중단되지 않습니다. – Evk

관련 문제