2

Im Folgenden finden Sie eine Aktualisierung des Async-Cache und der Datenbank mithilfe des Transaktionsbereichs. Ich kann TransactionScopeAsyncFlowOption.Enabled nicht verwenden, das in v 4.5.1 eingeführt wurde, da der Apache Ignite.Net Cache, den ich verwende, es nicht unterstützt. Ich habe versucht, eine Abhilfe zu finden, indem Sie die aktuellen Synchronization Context Erfassung und dann Synchronization Context Send Methode explizit mit, die Transaktion abzuschließen, aber das funktioniert nicht, wie ich noch Transaction scope must be disposed on same thread it was createdAktivieren von Async TransactionScope ohne TransactionScopeAsyncFlowOption.Enabled

Jeder Vorschlag, einen Fehler wie etwa zu gehen, um die Async Update zu erreichen. einer der Vorschlag von Apache Ignite Unterstützung ist wie etwas zu verwenden:

Task.WhenAll(cacheUpdate, databaseUpdate).Wait(), aber das würde Async Code Sync machen, also nicht einer der besten Option

public async Task Update() 
{ 
    // Capture Current Synchronization Context 
    var sc = SynchronizationContext.Current; 

    TransactionOptions tranOptions = new TransactionOptions(); 
    tranOptions.IsolationLevel = System.Transactions.IsolationLevel.RepeatableRead; 


    using (var ts = new TransactionScope()) 
    { 
     // Do Cache Update Operation as Async 
     Task cacheUpdate = // Update Cache Async 

     // Do Database Update Operation as Async 
     Task databaseUpdate = // Update Database Async 

     await Task.WhenAll(cacheUpdate, databaseUpdate); 

       sc.Send(new SendOrPostCallback(
       o => 
       { 
        ts.Complete(); 
       }), sc);   
    } 
} 
+3

ich nicht ganz laufen zu bekommen, warum Sie nicht TransactionScopeAsyncFlowOption.Enabled verwenden können. Sie müssen auf .NET 4.0 laufen? – Evk

+0

Dies würde Cache Update Async-Methoden verwenden, die von Apache Ignite.Net zur Verfügung gestellt werden, die mit dem Java-Prozess kommunizieren und gemäß denen sie diese Option nicht unterstützen. Ich kenne nicht alle internen Details von Warum –

+2

Wusste nicht, dass diese Funktion explizite Unterstützung von einer Drittanbieterkomponente erfordert. – Evk

Antwort

1

Nach fairen Betrag von Such über Blogs und Artikel, ich habe den folgenden Blog von Stephen Toub gefunden, hilft bei der Continuation of Async-Methode auf genau den gleichen Thread, so dass die Transaktion Scope Problem zu vermeiden. Jetzt brauche ich nicht TransactionScopeAsyncFlowOption.Enabled die Async Methoden in der TransactionScope

https://blogs.msdn.microsoft.com/pfxteam/2012/01/20/await-synchronizationcontext-and-console-apps/

void Main() 
{ 
    // Modified Async Scheduler for Continuations to work on Exactly same thread 
    // Required in the case same Thread is required for Task Continuation post await 
    Run(async() => await DemoAsync()); 

    "Main Complete".Dump(); 
} 

static async Task DemoAsync() 
{ 
    // Transcation Scope test (shall dispose 
    using (var ts = new TransactionScope()) 
    {    
     await Cache + Database Async update 
     ts.Complete(); 
     "Transaction Scope Complete".Dump(); 
    } 
} 

// Run Method to utilize the Single Thread Synchronization context, thus ensuring we can 
// Control the threads/Synchronization context post await, cotinuation run of specific set of threads 

public static void Run(Func<Task> func) 
{ 
    // Fetch Current Synchronization context 
    var prevCtx = SynchronizationContext.Current; 

    try 
    { 
     // Create SingleThreadSynchronizationContext 
     var syncCtx = new SingleThreadSynchronizationContext(); 

     // Set SingleThreadSynchronizationContext 
     SynchronizationContext.SetSynchronizationContext(syncCtx); 

     // Execute Func<Task> to fetch the task to be executed 
     var t = func(); 

     // On Continuation complete the SingleThreadSynchronizationContext 
     t.ContinueWith(
      delegate { syncCtx.Complete(); }, TaskScheduler.Default); 

     // Ensure that SingleThreadSynchronizationContext run on a single thread 
     // Execute a Task and its continuation on same thread 
     syncCtx.RunOnCurrentThread(); 

     // Fetch Result if any 
     t.GetAwaiter().GetResult(); 
    } 
    // Reset the Previous Synchronization Context 
    finally { SynchronizationContext.SetSynchronizationContext(prevCtx); } 
} 

// Overriden Synchronization context, using Blocking Collection Consumer/Producer model 
// Ensure that same Synchronization context/Thread/set of threads are maintained 
// In this case we main a single thread for continuation post await 

private sealed class SingleThreadSynchronizationContext : SynchronizationContext 
{ 
    // BlockingCollection Consumer Producer Model 
    private readonly BlockingCollection<KeyValuePair<SendOrPostCallback, object>> 
     m_queue = new BlockingCollection<KeyValuePair<SendOrPostCallback, object>>(); 

    // Override Post, which is called during Async continuation 
    // Send is for Synchronous continuation 
    public override void Post(SendOrPostCallback d, object state) 
    { 
     m_queue.Add(
      new KeyValuePair<SendOrPostCallback, object>(d, state)); 
    } 

    // RunOnCurrentThread, does the job if fetching object from BlockingCollection and execute it 
    public void RunOnCurrentThread() 
    { 
     KeyValuePair<SendOrPostCallback, object> workItem; 
     while (m_queue.TryTake(out workItem, Timeout.Infinite)) 
      workItem.Key(workItem.Value); 
    } 

    // Compete the SynchronizationContext 
    public void Complete() { m_queue.CompleteAdding(); } 
}