2009-06-11 6 views
25

코드 블록이 TransactionScope 안에 있는지 가장 좋은 방법은 무엇입니까?
Transaction.Current는이를 수행 할 수있는 확실한 방법입니까, 아니면 미묘한 차이가 있습니까?
리플렉션을 사용하여 내부 ContextData.CurrentData.CurrentScope (System.Transactions에 있음)에 액세스 할 수 있습니까? 그렇다면 어떻게?코드가 TransactionScope 안에 있는지 어떻게 알 수 있습니까?

답변

4

더 신뢰할 수있는 방법이다 (I 말했듯이, Transaction.Current 수동으로 설정 될 수 있으며, 그것은 항상 우리가 정말 의미하지 않는다 TransactionScope에서). 리플렉션을 통해이 정보를 얻을 수도 있지만 IL을 내보내는 것은 리플렉션보다 100 배 빠르게 작동합니다.

private Func<TransactionScope> _getCurrentScopeDelegate; 

bool IsInsideTransactionScope 
{ 
    get 
    { 
    if (_getCurrentScopeDelegate == null) 
    { 
     _getCurrentScopeDelegate = CreateGetCurrentScopeDelegate(); 
    } 

    TransactionScope ts = _getCurrentScopeDelegate(); 
    return ts != null; 
    } 
} 

private Func<TransactionScope> CreateGetCurrentScopeDelegate() 
{ 
    DynamicMethod getCurrentScopeDM = new DynamicMethod(
    "GetCurrentScope", 
    typeof(TransactionScope), 
    null, 
    this.GetType(), 
    true); 

    Type t = typeof(Transaction).Assembly.GetType("System.Transactions.ContextData"); 
    MethodInfo getCurrentContextDataMI = t.GetProperty(
    "CurrentData", 
    BindingFlags.NonPublic | BindingFlags.Static) 
    .GetGetMethod(true); 

    FieldInfo currentScopeFI = t.GetField("CurrentScope", BindingFlags.NonPublic | BindingFlags.Instance); 

    ILGenerator gen = getCurrentScopeDM.GetILGenerator(); 
    gen.Emit(OpCodes.Call, getCurrentContextDataMI); 
    gen.Emit(OpCodes.Ldfld, currentScopeFI); 
    gen.Emit(OpCodes.Ret); 

    return (Func<TransactionScope>)getCurrentScopeDM.CreateDelegate(typeof(Func<TransactionScope>)); 
} 

[Test] 
public void IsInsideTransactionScopeTest() 
{ 
    Assert.IsFalse(IsInsideTransactionScope); 
    using (new TransactionScope()) 
    { 
    Assert.IsTrue(IsInsideTransactionScope); 
    } 
    Assert.IsFalse(IsInsideTransactionScope); 
} 
+1

4 년 동안 프로덕션 환경에서이 코드를 사용한 후 "신뢰할 수있는"정의를 변경했는지 궁금합니다. –

+0

Transaction.Current가 신뢰할 수없는 경우 왜 .Net Devs는 읽기 전용으로 두지 않았습니까? 그 구현을 보셨습니까? –

+3

.Net 4.5에 "CurrentData"가 "TLSCurrentData"로 바뀌 었습니다. –

35

Transaction.Current은 신뢰할 수 있어야합니다. 이도 억제 거래와 함께 잘 작동에 난 그냥 확인했습니다

여기
Console.WriteLine(Transaction.Current != null); // false 
using (TransactionScope tran = new TransactionScope()) 
{ 
    Console.WriteLine(Transaction.Current != null); // true 
    using (TransactionScope tran2 = new TransactionScope(
      TransactionScopeOption.Suppress)) 
    { 
     Console.WriteLine(Transaction.Current != null); // false 
    } 
    Console.WriteLine(Transaction.Current != null); // true 
} 
Console.WriteLine(Transaction.Current != null); // false 
+0

나는 우리가 TransactionScope에 없더라도 Transaction.Current 속성을 설정할 수 있다는 것을 의미합니다. – nightcoder

+1

TransactionScope가 완료되었지만 아직 처리되지 않은 경우 Syste.Transactions.Transaction.Curre가 예외를 throw합니다 –

관련 문제