2

Voici la mise en cache Async et la mise à jour de la base de données à l'aide de Transaction Scope. Je ne peux pas utiliser TransactionScopeAsyncFlowOption.Enabled introduit dans la version 4.5.1, car le cache Apache Ignite.Net que j'utilise ne le supporte pas. J'ai essayé de trouver une solution en captant le courant Synchronization Context puis explicitement en utilisant la méthode Synchronization Context Send pour compléter la transaction, mais cela ne fonctionne pas comme je reçois encore une erreur Transaction scope must be disposed on same thread it was createdActiver Async TransactionScope sans TransactionScopeAsyncFlowOption.Enabled

Toute suggestion comment s'y prendre pour atteindre l'Async Update. une de la suggestion par Apache Ignite support est d'utiliser quelque chose comme:

Task.WhenAll(cacheUpdate, databaseUpdate).Wait(), mais qui rendrait le code Async Sync, donc pas l'une des meilleures options

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

Je ne comprends pas bien pourquoi vous ne pouvez pas utiliser TransactionScopeAsyncFlowOption.Enabled. Vous devez exécuter .NET 4.0? – Evk

+0

Ceci utiliserait les méthodes Cache Update Async exposées par Apache Ignite.Net, qui communiquent avec le processus Java et qui ne supportent pas cette option. Je ne suis pas au courant de tous les détails internes de Pourquoi –

+2

Je ne savais pas que cette fonctionnalité nécessite un soutien explicite de tout composant tiers. – Evk

Répondre

1

Après quantité de recherche sur les blogs et article, j'ai trouvé le blog suivant par Stephen Toub, aide à atteindre la continuation de la méthode Async sur exactement le même fil, évitant ainsi le problème de la portée de la transaction. Maintenant, je ne ai pas besoin TransactionScopeAsyncFlowOption.Enabled pour obtenir les méthodes Async exécuter dans le 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(); } 
}