Поделиться через


Привязка MSMQ с поддержкой транзакций

В этом образце показано, как осуществлять транзакционное взаимодействие с использованием очередей с помощью очереди сообщений (MSMQ).

ms751493.note(ru-ru,VS.100).gifПримечание
Процедура установки и инструкции по построению для данного образца приведены в конце этого раздела.

При использовании очередей клиент взаимодействует со службой посредством очереди. Конкретно, клиент отправляет сообщения в очередь. Служба получает сообщения из очереди. Поэтому при взаимодействии посредством очереди клиенту и службе не обязательно работать одновременно.

При использовании транзакций для отправки и получения сообщений это фактически две отдельные транзакции. При отправке клиентом сообщений в области транзакции эта транзакция локальна для клиента и диспетчера очереди клиента. При получении службой сообщений в области транзакции эта транзакция локальна для службы и диспетчера принимающей очереди. Очень важно помнить, что клиент и служба не участвуют в одной транзакции, а используют разные транзакции при выполнении операций с очередью (например, отправки и получения).

В этом образце клиент отправляет службе пакет сообщений из области транзакции. Сообщения, отправленные в очередь, принимаются после этого службой в области транзакции, определенной службой.

Контракт службы — IOrderProcessor, как показано в следующем образце кода. Интерфейс определяет одностороннюю службу, которую можно использовать с очередями.

[ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples")]
public interface IOrderProcessor
{
    [OperationContract(IsOneWay = true)]
    void SubmitPurchaseOrder(PurchaseOrder po);
}

Поведение службы определяет поведение операции со значением TransactionScopeRequired, равным true. Это обеспечивает использование любыми диспетчерами ресурсов, которыми пользуется метод, той же области транзакции, которая использовалась для получения сообщения из очереди. Кроме того, этим гарантируется возврат сообщения в очередь, если метод создаст исключение. Если не установить такое поведение операции, канал в очереди создает транзакцию для чтения сообщения из очереди и автоматически фиксирует ее перед передачей, поэтому при ошибке операции сообщение теряется. Обычная схема для операций служб заключается в зачислении транзакции, которая используется для чтения сообщения из очереди, как показано в следующем коде.

    // This service class that implements the service contract.
    // This added code writes output to the console window.
    public class OrderProcessorService : IOrderProcessor
    {
        [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
        public void SubmitPurchaseOrder(PurchaseOrder po)
        {
            Orders.Add(po);
            Console.WriteLine("Processing {0} ", po);
        }
     …
   }

Служба является резидентной. При работе с транспортом MSMQ используемую очередь следует создавать заранее. Это можно сделать вручную или с помощью кода. В данном образце служба содержит код для проверки наличия очереди и ее создания, если очереди нет. Имя очереди считывается из файла конфигурации. Средство Служебное средство ServiceModel Metadata Utility Tool (Svcutil.exe) с помощью базового адреса создает для службы прокси.

// Host the service within this EXE console application.
public static void Main()
{
    // Get the MSMQ queue name from appSettings in configuration.
    string queueName = ConfigurationManager.AppSettings["queueName"];

    // Create the transacted MSMQ queue if necessary.
    if (!MessageQueue.Exists(queueName))
        MessageQueue.Create(queueName, true);

    // Create a ServiceHost for the OrderProcessorService type.
    using (ServiceHost serviceHost = new ServiceHost(typeof(OrderProcessorService)))
    {
        // Open the ServiceHost to create listeners and start listening for messages.
        serviceHost.Open();

        // The service can now be accessed.
        Console.WriteLine("The service is ready.");
        Console.WriteLine("Press <ENTER> to terminate service.");
        Console.WriteLine();
        Console.ReadLine();

        // Close the ServiceHost to shut down the service.
        serviceHost.Close();
    }
}

Имя очереди MSMQ задается в разделе appSettings файла конфигурации, как показано в следующем образце конфигурации.

<appSettings>
    <add key="queueName" value=".\private$\ServiceModelSamplesTransacted" />
</appSettings>
ms751493.note(ru-ru,VS.100).gifПримечание
В имени очереди для определения локального компьютера используется точка (.), а при создании очереди с помощью System.Messaging в пути в качестве разделителей используются символы обратной косой черты. Конечная точка Windows Communication Foundation (WCF) использует адрес очереди со схемой net.msmq, для обозначения локального компьютера служит имя «localhost», а в пути в качестве разделителей используется символ косой черты.

Клиент создает область транзакции. Связь с очередью происходит в области транзакции, поэтому она обрабатывается как единый модуль, в котором либо все сообщения отправляются в очередь, либо в очередь не отправляется ни одного сообщения. Транзакция фиксируется вызовом метода Complete для области транзакции.

// Create a client.
OrderProcessorClient client = new OrderProcessorClient();

// Create the purchase order.
PurchaseOrder po = new PurchaseOrder();
po.CustomerId = "somecustomer.com";
po.PONumber = Guid.NewGuid().ToString();

PurchaseOrderLineItem lineItem1 = new PurchaseOrderLineItem();
lineItem1.ProductId = "Blue Widget";
lineItem1.Quantity = 54;
lineItem1.UnitCost = 29.99F;

PurchaseOrderLineItem lineItem2 = new PurchaseOrderLineItem();
lineItem2.ProductId = "Red Widget";
lineItem2.Quantity = 890;
lineItem2.UnitCost = 45.89F;

po.orderLineItems = new PurchaseOrderLineItem[2];
po.orderLineItems[0] = lineItem1;
po.orderLineItems[1] = lineItem2;

// Create a transaction scope.
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
{
    // Make a queued call to submit the purchase order.
    client.SubmitPurchaseOrder(po);
    // Complete the transaction.
    scope.Complete();
}

// Closing the client gracefully closes the connection and cleans up resources.
client.Close();

Console.WriteLine();
Console.WriteLine("Press <ENTER> to terminate client.");
Console.ReadLine();

Чтобы убедиться, что транзакции работают, измените клиент, преобразовав область транзакции в комментарий, как показано в следующем фрагменте кода, снова выполните построение решения и запустите клиент.

//scope.Complete();

Так как транзакция не завершена, сообщения не отправляются в очередь.

При выполнении образца операции клиента и службы отображаются в окнах консоли как службы, так и клиента. Можно видеть, как служба получает сообщения от клиента. Нажмите клавишу ВВОД в каждом окне консоли, чтобы закрыть службу и клиент. Обратите внимание, что поскольку используется очередь, клиенту и службе не обязательно быть запущенными и работать одновременно. Можно запустить клиент, выключить его, а затем запустить службу и все равно получить сообщения клиента.

The service is ready.
Press <ENTER> to terminate service.

Processing Purchase Order: 7b31ce51-ae7c-4def-9b8b-617e4288eafd
        Customer: somecustomer.com
        OrderDetails
                Order LineItem: 54 of Blue Widget @unit price: $29.99
                Order LineItem: 890 of Red Widget @unit price: $45.89
        Total cost of this order: $42461.56
        Order status: Pending

Настройка, построение и выполнение образца

  1. Убедитесь, что выполнена процедура, описанная в разделе Процедура однократной настройки образцов Windows Communication Foundation.

  2. При первом запуске служба проверит наличие очереди. Если очередь отсутствует, служба ее создаст. Можно сначала запустить службу, чтобы создать очередь, либо создать ее с помощью диспетчера очередей MSMQ. Чтобы создать очередь в Windows 2008, выполните следующие шаги.

    1. Откройте диспетчер сервера в Visual Studio 2010.

    2. Разверните вкладку Функции.

    3. Щелкните правой кнопкой мыши узел Очереди личных сообщений и выберите пункты Создать, Частная очередь.

    4. Установите флажок Транзакционная.

    5. В качестве имени новой очереди укажите ServiceModelSamplesTransacted.

  3. Чтобы создать выпуск решения на языке C# или Visual Basic .NET, следуйте инструкциям в разделе Построение образцов Windows Communication Foundation.

  4. Чтобы запустить образец на одном или нескольких компьютерах, следуйте инструкциям в разделе Running the Windows Communication Foundation Samples.

По умолчанию с привязкой NetMsmqBinding безопасность транспорта включена. Имеется два соответствующих свойства для обеспечения безопасности транспорта MSMQ: MsmqAuthenticationMode и MsmqProtectionLevel. По умолчанию устанавливается режим проверки подлинности Windows и уровень защиты Sign. Чтобы служба MSMQ обеспечивала возможности проверки подлинности и подписывания, она должна входить в домен, а также должна быть установлена функция интеграции MSMQ со службой каталогов Active Directory. Если запустить этот образец на компьютере, который не удовлетворяет этому условию, возникнет ошибка.

Выполнение образца на компьютере, входящем в рабочую группу, или без интеграции с Active Directory

  1. Если компьютер не входит в домен или не установлена интеграция с Active Directory, отключите безопасность транспорта, задав для режима проверки подлинности и уровня защиты значение None, как показано в следующем образце кода конфигурации.

    <system.serviceModel>
      <services>
        <service name="Microsoft.ServiceModel.Samples.OrderProcessorService"
                 behaviorConfiguration="OrderProcessorServiceBehavior">
          <host>
            <baseAddresses>
              <add baseAddress="https://localhost:8000/ServiceModelSamples/service"/>
            </baseAddresses>
          </host>
          <!-- Define NetMsmqEndpoint. -->
          <endpoint
              address="net.msmq://localhost/private/ServiceModelSamplesTransacted"
              binding="netMsmqBinding"
              bindingConfiguration="Binding1"
           contract="Microsoft.ServiceModel.Samples.IOrderProcessor" />
          <!-- The mex endpoint is explosed at https://localhost:8000/ServiceModelSamples/service/mex. -->
          <endpoint address="mex"
                    binding="mexHttpBinding"
                    contract="IMetadataExchange" />
        </service>
      </services>
    
      <bindings>
        <netMsmqBinding>
          <binding name="Binding1">
            <security mode="None" />
          </binding>
        </netMsmqBinding>
      </bindings>
    
        <behaviors>
          <serviceBehaviors>
            <behavior name="OrderProcessorServiceBehavior">
              <serviceMetadata httpGetEnabled="True"/>
            </behavior>
          </serviceBehaviors>
        </behaviors>
    
      </system.serviceModel>
    
  2. Перед выполнением образца убедитесь, что изменена конфигурация как сервера, так и клиента.

    ms751493.note(ru-ru,VS.100).gifПримечание
    Задание для securitymode значения None равнозначно заданию для безопасности MsmqAuthenticationMode, MsmqProtectionLevel и Message значения None.

ms751493.Important(ru-ru,VS.100).gif Примечание
Образцы уже могут быть установлены на компьютере. Перед продолжением проверьте следующий каталог (по умолчанию).

<диск_установки>:\WF_WCF_Samples

Если этот каталог не существует, перейдите на страницу Образцы Windows Communication Foundation (WCF) и Windows Workflow Foundation (WF) для .NET Framework 4, чтобы загрузить все образцы Windows Communication Foundation (WCF) и WF. Этот образец расположен в следующем каталоге.

<диск_установки>:\WF_WCF_Samples\WCF\Basic\Binding\Net\MSMQ\Transacted