Как сделать так, чтобы клиент служебной шины Azure не участвовал в внешней транзакции при отправке сообщения - PullRequest
0 голосов
/ 26 мая 2020

Я понимаю, что DT C не поддерживаются Azure служебной шиной, и если вы попытаетесь это сделать, вы получите следующее исключение: ' Локальные транзакции не поддерживаются другими диспетчерами ресурсов / DT C. '

Моя проблема в том, что мне нужно отправить сообщение на служебную шину, и код может быть выполнен в рамках транзакции вместе с возможными операциями с DB. Но служебная шина не обязательно должна быть частью этой транзакции; так что DT C здесь не нужен. Однако клиент служебной шины, кажется, автоматически участвует в внешней транзакции, которая повышает транзакцию до DT C.

Примеры:

Это работает правильно (код служебной шины является единственным в транзакции):

        using (var tx = new TransactionScope())
        {
            //A simple Azure Bus operation
            var builder = new ServiceBusConnectionStringBuilder(connectionString);
            var queueClient = new QueueClient(builder);
            var messageBody = new Message(Encoding.UTF8.GetBytes("Hello"));
            messageBody.MessageId = Guid.NewGuid().ToString("N");
            queueClient.SendAsync(messageBody).GetAwaiter().GetResult();                

            tx.Complete();
        }

Но с момента, когда другая система участвует (здесь Sql соединение), « DT C не поддерживаются Azure Service Bus"- выбрасывается исключение:

        using (var tx = new TransactionScope())
        {
            //A simple DB operation
            SqlConnection sqlConnection = new SqlConnection(dbConnectionString);
            sqlConnection.Open();
            SqlCommand cmd = new SqlCommand("INSERT INTO [dbo].[Table_1]([Name]) values ('Hello')", sqlConnection);
            cmd.ExecuteNonQuery();

            //A simple Azure Bus operation
            var builder = new ServiceBusConnectionStringBuilder(connectionString);
            var queueClient = new QueueClient(builder);
            var messageBody = new Message(Encoding.UTF8.GetBytes("Hello"));
            messageBody.MessageId = Guid.NewGuid().ToString("N");
            queueClient.SendAsync(messageBody).GetAwaiter().GetResult();

            queueClient.CloseAsync().GetAwaiter().GetResult();
            sqlConnection.Close();

            tx.Complete();
        }

Эта ошибка понятна и уже объяснена здесь . Но есть ли способ указать клиенту служебной шины игнорировать внешнюю транзакцию?

1 Ответ

1 голос
/ 26 мая 2020

Вам нужно будет подавить внешнюю транзакцию и обернуть код служебной шины следующим образом:

public async Task Method()
{
  SqlConnection sqlConnection = new SqlConnection(dbConnectionString);
  sqlConnection.Open();

  using (var tx = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
  {
    SqlCommand cmd = new SqlCommand("INSERT INTO [dbo].[Table_1]([Name]) values 
('Hello')", sqlConnection);
    await cmd.ExecuteNonQueryAsync();

    using (var tx = new TransactionScope(TransactionScopeOption.Suppress, TransactionScopeAsyncFlowOption.Enabled))
    {
       var builder = new ServiceBusConnectionStringBuilder(connectionString);
       var queueClient = new QueueClient(builder);
       var messageBody = new Message(Encoding.UTF8.GetBytes("Hello"));
       messageBody.MessageId = Guid.NewGuid().ToString("N");
       queueClient.SendAsync(messageBody).GetAwaiter().GetResult();

       queueClient.CloseAsync().GetAwaiter().GetResult();

       tx.Complete();
    }

    tx.Complete();
  }
  sqlConnection.Close();
}

Обратите внимание, что

  1. Вы не должны повторно создавать клиента очереди каждый раз. время. Сохраните его для соображений производительности.
  2. Не используйте асинхронные API в синхронном коде. Скорее преобразуйте ваш метод в asyn c. Операции SQL привязаны к вводу-выводу, как и служебная шина. Лучше, чтобы метод был асинхронным.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...