обмен данными Two-Way

В примереTwo-Way показано, как выполнять транзакционный двусторонний обмен данными в очереди через MSMQ. В этом примере используется привязка netMsmqBinding . В этом случае служба — это локальное консольное приложение, которое позволяет наблюдать за службой, получающей сообщения в очереди.

Замечание

Процедура установки и инструкции по сборке для этого примера находятся в конце этого раздела.

Этот пример основан на передаваемой привязке MSMQ.

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

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

Контракт IOrderProcessor обслуживания определяет односторонние операции обслуживания, подходящие для использования очередей. Операция службы включает конечную точку ответа, которую используют для отправки статусов заказа. Конечная точка ответа — это URI очереди для отправки состояния заказа обратно клиенту. Приложение обработки заказов реализует этот контракт.

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

Контракт ответа для отправки статуса заказа указывается клиентом. Клиент реализует контракт состояния заказа. Служба использует созданный прокси-сервер этого контракта для отправки состояния заказа клиенту.

[ServiceContract]
public interface IOrderStatus
{
    [OperationContract(IsOneWay = true)]
    void OrderStatus(string poNumber, string status);
}

Операция службы обрабатывает отправленный заказ на покупку. OperationBehaviorAttribute применяется к операции службы, чтобы указать на автоматическое участие в транзакции, которая используется для получения сообщения из очереди, и автоматическое завершение транзакции при завершении операции службы. Класс Orders инкапсулирует функции обработки заказов. В этом случае он добавляет заказ на покупку в словарь. Транзакция, в которую включена операция службы, доступна операциям в Orders классе.

Операция службы, помимо обработки отправленного заказа на покупку, возвращает клиенту ответы на состояние заказа.

[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public void SubmitPurchaseOrder(PurchaseOrder po, string reportOrderStatusTo)
{
    Orders.Add(po);
    Console.WriteLine("Processing {0} ", po);
    Console.WriteLine("Sending back order status information");
    NetMsmqBinding msmqCallbackBinding = new NetMsmqBinding("ClientCallbackBinding");
    OrderStatusClient client = new OrderStatusClient(msmqCallbackBinding, new EndpointAddress(reportOrderStatusTo));

    // Please note that the same transaction that is used to dequeue the purchase order is used
    // to send back order status.
    using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
    {
        client.OrderStatus(po.PONumber, po.Status);
        scope.Complete();
    }
    //Close the client.
    client.Close();
}

Имя очереди MSMQ указывается в разделе appSettings файла конфигурации. Конечная точка службы определена в разделе System.ServiceModel файла конфигурации.

Замечание

Имя очереди MSMQ и адрес конечной точки используют несколько разные соглашения об адресации. Имя очереди MSMQ использует точку (.) для локального компьютера и обратную косую черту в пути. Адрес конечной точки Windows Communication Foundation (WCF) задает схему net.msmq, использует localhost для локального компьютера и использует косую черту в пути. Чтобы прочитать из очереди, размещенной на удаленном компьютере, замените "." и "localhost" на название удаленного компьютера.

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

// Host the service within this EXE console application.
public static void Main()
{
    // Get 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();
    }
}

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

// Create a ServiceHost for the OrderStatus service type.
using (ServiceHost serviceHost = new ServiceHost(typeof(OrderStatusService)))
{

    // Open the ServiceHostBase to create listeners and start listening for order status messages.
    serviceHost.Open();

    // Create the purchase order.
    ...

    // Create a client with given client endpoint configuration.
    OrderProcessorClient client = new OrderProcessorClient("OrderProcessorEndpoint");

    //Create a transaction scope.
    using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
    {
        string hostName = Dns.GetHostName();

        // Make a queued call to submit the purchase order.
        client.SubmitPurchaseOrder(po, "net.msmq://" + hostName + "/private/ServiceModelSamplesTwo-way/OrderStatus");

        // Complete the transaction.
        scope.Complete();
    }

    //Close down the client.
    client.Close();

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

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

Клиентский IOrderStatus код реализует контракт для получения состояния заказа от службы. В этом случае он выводит состояние заказа.

[ServiceBehavior]
public class OrderStatusService : IOrderStatus
{
    [OperationBehavior(TransactionAutoComplete = true,
                        TransactionScopeRequired = true)]
    public void OrderStatus(string poNumber, string status)
    {
        Console.WriteLine("Status of order {0}:{1} ", poNumber ,
                                                           status);
    }
}

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

<appSettings>
  <!-- Use appSetting to configure MSMQ queue name. -->
  <add key="queueName" value=".\private$\ServiceModelSamplesTwo-way/OrderStatus" />
</appSettings>

<system.serviceModel>

  <services>
    <service
       name="Microsoft.ServiceModel.Samples.OrderStatusService">
      <!-- Define NetMsmqEndpoint -->
      <endpoint address="net.msmq://localhost/private/ServiceModelSamplesTwo-way/OrderStatus"
                binding="netMsmqBinding"
                contract="Microsoft.ServiceModel.Samples.IOrderStatus" />
    </service>
  </services>

  <client>
    <!-- Define NetMsmqEndpoint -->
    <endpoint name="OrderProcessorEndpoint"
              address="net.msmq://localhost/private/ServiceModelSamplesTwo-way/OrderProcessor"
              binding="netMsmqBinding"
              contract="Microsoft.ServiceModel.Samples.IOrderProcessor" />
  </client>

</system.serviceModel>

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

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

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

Processing Purchase Order: 124a1f69-3699-4b16-9bcc-43147a8756fc
        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

Sending back order status information

Клиент отображает сведения о состоянии заказа, отправленные службой.

Press <ENTER> to terminate client.
Status of order 124a1f69-3699-4b16-9bcc-43147a8756fc:Pending

Настройка, сборка и запуск примера

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

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

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

    Замечание

    Если вы используете Svcutil.exe для повторного создания конфигурации для этого примера, обязательно измените имена конечных точек в конфигурации клиента, чтобы соответствовать коду клиента.

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

Запуск примера на компьютере, присоединенном к рабочей группе или без интеграции Active Directory

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

    <configuration>
    
      <appSettings>
        <!-- Use appSetting to configure MSMQ queue name. -->
        <add key="queueName" value=".\private$\ServiceModelSamplesTwo-way/OrderProcessor" />
      </appSettings>
    
      <system.serviceModel>
        <services>
          <service
              name="Microsoft.ServiceModel.Samples.OrderProcessorService">
            <!-- Define NetMsmqEndpoint -->
            <endpoint address="net.msmq://localhost/private/ServiceModelSamplesTwo-way/OrderProcessor"
                      binding="netMsmqBinding"
                      bindingConfiguration="TransactedBinding"
                      contract="Microsoft.ServiceModel.Samples.IOrderProcessor" />
          </service>
        </services>
    
        <bindings>
          <netMsmqBinding>
            <binding name="TransactedBinding" >
             <security mode="None" />
            </binding>
          </netMsmqBinding>
        </bindings>
    
      </system.serviceModel>
    
    </configuration>
    
  2. Отключение безопасности для конфигурации клиента приводит к следующему:

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <appSettings>
        <!-- Use appSetting to configure MSMQ queue name. -->
        <add key="queueName" value=".\private$\ServiceModelSamplesTwo-way/OrderStatus" />
      </appSettings>
    
      <system.serviceModel>
    
        <services>
          <service
             name="Microsoft.ServiceModel.Samples.OrderStatusService">
            <!-- Define NetMsmqEndpoint -->
            <endpoint address="net.msmq://localhost/private/ServiceModelSamplesTwo-way/OrderStatus"
                      binding="netMsmqBinding"
                      bindingConfiguration="TransactedBinding" contract="Microsoft.ServiceModel.Samples.IOrderStatus" />
          </service>
        </services>
    
        <client>
          <!-- Define NetMsmqEndpoint -->
          <endpoint name="OrderProcessorEndpoint"
                    address="net.msmq://localhost/private/ServiceModelSamplesTwo-way/OrderProcessor"
                    binding="netMsmqBinding"
                    bindingConfiguration="TransactedBinding"
                    contract="Microsoft.ServiceModel.Samples.IOrderProcessor" />
        </client>
    
        <bindings>
          <netMsmqBinding>
            <binding name="TransactedBinding" >
             <security mode="None" />
            </binding>
          </netMsmqBinding>
        </bindings>
    
      </system.serviceModel>
    
    </configuration>
    
  3. Служба для этого примера создает привязку в объекте OrderProcessorService. Добавьте строку кода после создания экземпляра привязки, чтобы задать для режима безопасности значение None.

    NetMsmqBinding msmqCallbackBinding = new NetMsmqBinding();
    msmqCallbackBinding.Security.Mode = NetMsmqSecurityMode.None;
    
  4. Перед запуском примера убедитесь, что вы измените конфигурацию как на сервере, так и на клиенте.

    Замечание

    Установка security mode на None эквивалентна установке безопасности MsmqAuthenticationMode, MsmqProtectionLevel или Message на None.