Làm cho TransactionScope hoạt động với async / await


114

Tôi đang cố gắng tích hợp async/ awaitvào xe buýt dịch vụ của chúng tôi. Tôi đã triển khai SingleThreadSynchronizationContextdựa trên ví dụ này http://blogs.msdn.com/b/pfxteam/archive/2012/01/20/10259049.aspx .

Và nó hoạt động tốt, ngoại trừ một điều: TransactionScope. Tôi chờ đợi những thứ bên trong TransactionScopevà nó phá vỡ TransactionScope.

TransactionScopedường như không hoạt động tốt với async/ await, chắc chắn vì nó lưu trữ mọi thứ trong chuỗi sử dụng ThreadStaticAttribute. Tôi nhận được ngoại lệ này:

"TransactionScope được lồng không chính xác.".

Tôi đã cố gắng lưu TransactionScopedữ liệu trước khi xếp hàng nhiệm vụ và khôi phục nó trước khi chạy nó nhưng có vẻ như nó không thay đổi được gì. Và TransactionScopemã là một mớ hỗn độn, vì vậy thật khó hiểu chuyện gì đang xảy ra ở đó.

Có cách nào để làm cho nó hoạt động? Có một số thay thế cho TransactionScope?


Đây là một mã rất đơn giản để tạo lại lỗi TransactionScope pastebin.com/Eh1dxG4a ngoại trừ trường hợp ngoại lệ ở đây là Giao dịch bị hủy bỏ
Yann

Bạn có thể chỉ sử dụng một giao dịch SQL thông thường không? Hay bạn đang mở rộng nhiều tài nguyên?
Marc Gravell

Tôi đang mở rộng nhiều nguồn tin tức
Yann

Có vẻ như bạn sẽ cần phải chuyển phạm vi vào phương thức không đồng bộ của mình hoặc cung cấp cho nó một cách để truy xuất nó từ một số loại ngữ cảnh phổ biến được xác định với đơn vị công việc của bạn.
Bertrand Le Roy

Bạn sẽ cần một chuỗi riêng với chuỗi riêng SingleThreadSynchronizationContextcho mỗi cấp cao nhất TransactionScope.
Stephen Cleary

Câu trả lời:


161

Trong .NET Framework 4.5.1, có một tập hợp các hàm tạo mớiTransactionScope nhận TransactionScopeAsyncFlowOptiontham số.

Theo MSDN, nó cho phép luồng giao dịch xuyên suốt chuỗi liên tục.

Tôi hiểu rằng nó có nghĩa là cho phép bạn viết mã như thế này:

// transaction scope
using (var scope = new TransactionScope(... ,
  TransactionScopeAsyncFlowOption.Enabled))
{
  // connection
  using (var connection = new SqlConnection(_connectionString))
  {
    // open connection asynchronously
    await connection.OpenAsync();

    using (var command = connection.CreateCommand())
    {
      command.CommandText = ...;

      // run command asynchronously
      using (var dataReader = await command.ExecuteReaderAsync())
      {
        while (dataReader.Read())
        {
          ...
        }
      }
    }
  }
  scope.Complete();
}

10

Hơi trễ để có câu trả lời nhưng tôi đang gặp vấn đề tương tự với MVC4 và tôi đã cập nhật dự án của mình từ 4.5 lên 4.5.1 bằng cách nhấp chuột phải vào dự án đi đến thuộc tính. Chọn khung mục tiêu thay đổi tab ứng dụng thành 4.5.1 và sử dụng giao dịch như sau.

using (AccountServiceClient client = new AccountServiceClient())
using (TransactionScope scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
}


6

Bạn có thể sử dụng DependentTransaction được tạo bởi phương thức Transaction.DependentClone () :

static void Main(string[] args)
{
  // ...

  for (int i = 0; i < 10; i++)
  {

    var dtx = Transaction.Current.DependentClone(
        DependentCloneOption.BlockCommitUntilComplete);

    tasks[i] = TestStuff(dtx);
  }

  //...
}


static async Task TestStuff(DependentTransaction dtx)
{
    using (var ts = new TransactionScope(dtx))
    {
        // do transactional stuff

        ts.Complete();
    }
    dtx.Complete();
}

Quản lý đồng tiền với DependentTransaction

http://adamprescott.net/2012/10/04/transactionscope-in-multi-threaded-application/


2
Nhiệm vụ con mẫu của Adam Prescott không được đánh dấu là không đồng bộ. Nếu bạn thay thế "do giao dịch nội dung" bằng một cái gì đó giống như await Task.Delay(500)mẫu này cũng sẽ không thành công TransactionScope nested incorrectlybởi vì TransactionScope ngoài cùng (không được hiển thị trong ví dụ trên) thoát khỏi phạm vi trước khi nhiệm vụ con hoàn thành đúng cách. Thay thế awaitbằng Task.Wait()và nó hoạt động, nhưng sau đó bạn đã mất những lợi ích của async.
mdisibio

Đây là một cách khó hơn để giải quyết vấn đề. TransactionScope là để ẩn tất cả hệ thống ống nước đó.
Eniola
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.