2009-06-11 9 views

Respuesta

4

Aquí es la forma más fiable (como ya he dicho, Transaction.Current se puede ajustar de forma manual y no siempre quiere decir que estamos realmente en TransactionScope). También es posible obtener esta información con reflexión, pero emitir IL funciona 100 veces más rápido que la reflexión.

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

Me pregunto si ha cambiado su definición de "confiable" después de usar este código en producción durante cuatro años. –

+0

Si Transaction.Current no es confiable, ¿por qué no lo hizo .Net Devs lo dejó solo? ¿Has mirado su implementación? –

+3

Aparece en .Net 4.5 "CurrentData" se ha cambiado el nombre a "TLSCurrentData" –

35

Transaction.Current debe ser confiable; Yo sólo he comprobado, en este funciona bien con las transacciones suprimidas, también:

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

Quiero decir que la propiedad Transaction.Current se puede establecer incluso si no estamos en TransactionScope. – nightcoder

+1

Si TransactionScope está completo, pero aún no se elimina, Syste.Transactions.Transaction.Curre arroja una excepción –

Cuestiones relacionadas