Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/265.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 启用不带TransactionScopeAsyncFlowOption的异步TransactionScope。已启用_C#_Asynchronous_Async Await_Task Parallel Library_Transactionscope - Fatal编程技术网

C# 启用不带TransactionScopeAsyncFlowOption的异步TransactionScope。已启用

C# 启用不带TransactionScopeAsyncFlowOption的异步TransactionScope。已启用,c#,asynchronous,async-await,task-parallel-library,transactionscope,C#,Asynchronous,Async Await,Task Parallel Library,Transactionscope,下面是使用事务作用域的异步缓存和数据库更新。我不能使用V4.5.1中引入的TransactionScopeAsyncFlowOption.Enabled,因为我使用的Apache Ignite.Net缓存不支持它。我尝试通过捕获当前的同步上下文,然后显式地使用同步上下文发送方法来完成事务,以找到解决方法,但这不起作用,因为我仍然收到一个错误事务范围必须在创建它的同一线程上处理 关于如何实现异步更新的任何建议。Apache Ignite support的建议之一是使用以下内容: Task.When

下面是使用事务作用域的异步缓存和数据库更新。我不能使用V4.5.1中引入的
TransactionScopeAsyncFlowOption.Enabled
,因为我使用的Apache Ignite.Net缓存不支持它。我尝试通过捕获当前的
同步上下文
,然后显式地使用
同步上下文发送
方法来完成事务,以找到解决方法,但这不起作用,因为我仍然收到一个错误
事务范围必须在创建它的同一线程上处理

关于如何实现
异步更新
的任何建议。Apache Ignite support的建议之一是使用以下内容:

Task.WhenAll(cacheUpdate,databaseUpdate).Wait()
,但这会使异步代码同步,因此不是最佳选项之一

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);        
    }
}

在对博客和文章进行了大量搜索之后,我发现Stephen Toub的以下博客有助于在完全相同的线程上实现异步方法的延续,从而避免了事务范围问题。现在我不需要
TransactionScopeAsyncFlowOption.Enabled
TransactionScope

void Main()
{
//修改了异步调度程序,使Continuations可以在完全相同的线程上工作
//在任务继续post WAIT需要相同线程的情况下需要
运行(async()=>等待DemoAsync());
“主完成”。转储();
}
静态异步任务demosync()
{
//交易范围测试(应处理)
使用(var ts=new TransactionScope())
{            
等待缓存+数据库异步更新
ts.完成();
“事务范围完成”。Dump();
}   
}
//Run方法来利用单线程同步上下文,从而确保
//控制特定线程集的线程/同步上下文post WAIT、持续运行
公共静态无效运行(Func Func)
{
//获取当前同步上下文
var prevCtx=SynchronizationContext.Current;
尝试
{
//创建SingleThreadSynchronizationContext
var syncCtx=新的SingleThreadSynchronizationContext();
//设置SingleThreadSynchronizationContext
SynchronizationContext.SetSynchronizationContext(syncCtx);
//Execute Func获取要执行的任务
var t=func();
//继续时,完成SingleThreadSynchronizationContext
t、 继续(
委托{syncCtx.Complete();},TaskScheduler.Default);
//确保SingleThreadSynchronizationContext在单个线程上运行
//在同一线程上执行任务及其继续
syncCtx.RunOnCurrentThread();
//获取结果(如果有)
t、 GetAwaiter().GetResult();
}
//重置上一个同步上下文
最后{SynchronizationContext.SetSynchronizationContext(prevCtx);}
}
//使用阻塞集合使用者/生产者模型重写同步上下文
//确保维护相同的同步上下文/线程/线程集
//在本例中,我们为continuation post wait主线程
私有密封类SingleThreadSynchronizationContext:SynchronizationContext
{
//封锁收集消费者-生产者模型
私有只读阻止集合
m_queue=new BlockingCollection();
//重写Post,在异步继续期间调用它
//发送用于同步继续
公共重写void Post(sendorpostd,对象状态)
{
m_queue.Add(
新的KeyValuePair(d,state));
}
//RunOnCurrentThread,如果从BlockingCollection获取对象,则执行该作业并执行它
public void RunOnCurrentThread()
{
键值对工作项;
while(m_queue.TryTake(out workItem,Timeout.Infinite))
工作项键(工作项值);
}
//竞争SynchronizationContext
public void Complete(){m_queue.CompleteAdding();}
}

我不太明白为什么不能使用TransactionScopeAsyncFlowOption.Enabled。您必须在.NET 4.0上运行?这将使用Apache Ignite.NET公开的缓存更新异步方法,这些方法与Java进程通信,并且根据它们,它们不支持此选项。我不知道为什么此功能需要ires从任何第三方组件获得了一些明确的支持。从他们的支持评论来看,如果我使用,也不例外,但根据他们的说法,他们还没有明确支持该功能。我想知道它必须在4.5.1之前的版本中实现,这对我来说已经足够好了,可以开始了。那么你的意思是如果你真的使用事务CopeAncySyncFlowOption.Enabled它运行良好,没有任何问题?
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(); }
}