Udostępnij za pośrednictwem


Komunikacja dwukierunkowa

W przykładzie dwukierunkowym pokazano, jak przeprowadzić dwukierunkową komunikację w kolejce za pośrednictwem usługi MSMQ. W tym przykładzie użyto netMsmqBinding powiązania. W takim przypadku usługa jest aplikacją konsolową self-hosted, która umożliwia obserwowanie usługi odbierających komunikaty w kolejce.

Uwaga

Procedura instalacji i instrukcje kompilacji dla tego przykładu znajdują się na końcu tego tematu.

Ten przykład jest oparty na transakcyjnym powiązaniu MSMQ.

W komunikacji w kolejce klient komunikuje się z usługą przy użyciu kolejki. Klient wysyła komunikaty do kolejki, a usługa odbiera komunikaty z kolejki. W związku z tym usługa i klient nie muszą być uruchomione w tym samym czasie, aby komunikować się przy użyciu kolejki.

W tym przykładzie pokazano komunikację dwukierunkową przy użyciu kolejek. Klient wysyła zamówienia zakupu do kolejki z zakresu transakcji. Usługa odbiera zamówienia, przetwarza zamówienie, a następnie wywołuje klienta ze stanem zamówienia z kolejki w zakresie transakcji. W celu ułatwienia dwukierunkowej komunikacji klient i usługa używają kolejek do kolejkowania zamówień i stanu zamówienia.

Kontrakt IOrderProcessor usługi definiuje jednokierunkowe operacje usług, które odpowiadają użyciu kolejkowania. Operacja usługi obejmuje punkt końcowy odpowiedzi, który ma być używany do wysyłania stanów zamówienia. Punkt końcowy odpowiedzi to identyfikator URI kolejki do wysłania stanu zamówienia z powrotem do klienta. Aplikacja przetwarzania zamówień implementuje ten kontrakt.

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

Umowa odpowiedzi do wysyłania stanu zamówienia jest określana przez klienta. Klient implementuje kontrakt stanu zamówienia. Usługa używa wygenerowanego serwera proxy tego kontraktu do wysyłania stanu zamówienia z powrotem do klienta.

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

Operacja usługi przetwarza przesłane zamówienie zakupu. Element OperationBehaviorAttribute jest stosowany do operacji usługi w celu określenia automatycznej rejestracji w transakcji używanej do odbierania komunikatu z kolejki i automatycznego uzupełniania transakcji po zakończeniu operacji usługi. Klasa Orders hermetyzuje funkcje przetwarzania zamówień. W tym przypadku dodaje zamówienie zakupu do słownika. Transakcja, w ramach którego znajduje się operacja usługi, jest dostępna dla operacji w Orders klasie .

Operacja usługi, oprócz przetwarzania przesłanego zamówienia zakupu, odpowiada z powrotem do klienta w stanie zamówienia.

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

Nazwa kolejki MSMQ jest określona w sekcji aplikacji Ustawienia pliku konfiguracji. Punkt końcowy usługi jest zdefiniowany w sekcji System.ServiceModel pliku konfiguracji.

Uwaga

Nazwa kolejki MSMQ i adres punktu końcowego używają nieco różnych konwencji adresowania. Nazwa kolejki MSMQ używa kropki (.) dla maszyny lokalnej i separatorów ukośników odwrotnych w ścieżce. Adres punktu końcowego programu Windows Communication Foundation (WCF) określa net.msmq: scheme, używa "localhost" dla maszyny lokalnej i używa ukośników w ścieżce. Aby odczytać z kolejki hostowanej na maszynie zdalnej, zastąp ciąg "." i "localhost" nazwą maszyny zdalnej.

Usługa jest hostowana samodzielnie. W przypadku korzystania z transportu MSMQ używana kolejka musi zostać utworzona z wyprzedzeniem. Można to zrobić ręcznie lub za pomocą kodu. W tym przykładzie usługa sprawdza istnienie kolejki i tworzy ją w razie potrzeby. Nazwa kolejki jest odczytywana z pliku konfiguracji. Adres podstawowy jest używany przez narzędzie ServiceModel Metadata Tool (Svcutil.exe) do wygenerowania serwera proxy do usługi.

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

Klient tworzy transakcję. Komunikacja z kolejką odbywa się w zakresie transakcji, powodując, że jest traktowana jako jednostka niepodzielna, w której wszystkie komunikaty kończą się powodzeniem lub niepowodzeniem.

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

Kod klienta implementuje IOrderStatus kontrakt w celu otrzymania stanu zamówienia z usługi. W takim przypadku wyświetla stan zamówienia.

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

Kolejka stanu zamówienia jest tworzona w metodzie Main . Konfiguracja klienta obejmuje konfigurację usługi stanu zamówienia do hostowania usługi stanu zamówienia, jak pokazano w poniższej przykładowej konfiguracji.

<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>

Po uruchomieniu przykładu działania klienta i usługi są wyświetlane zarówno w oknach konsoli usługi, jak i klienta. Usługa odbiera komunikaty od klienta. Naciśnij klawisz ENTER w każdym oknie konsoli, aby zamknąć usługę i klienta.

Usługa wyświetla informacje o zamówieniu zakupu i wskazuje, że wysyła stan zamówienia z powrotem do kolejki stanu zamówienia.

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

Klient wyświetla informacje o stanie zamówienia wysyłane przez usługę.

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

Aby skonfigurować, skompilować i uruchomić przykład

  1. Upewnij się, że wykonano procedurę instalacji jednorazowej dla przykładów programu Windows Communication Foundation.

  2. Aby skompilować wersję rozwiązania w języku C# lub Visual Basic .NET, postępuj zgodnie z instrukcjami w temacie Building the Windows Communication Foundation Samples (Tworzenie przykładów programu Windows Communication Foundation).

  3. Aby uruchomić przykład w konfiguracji pojedynczej lub między maszynami, postępuj zgodnie z instrukcjami w temacie Uruchamianie przykładów programu Windows Communication Foundation.

    Uwaga

    Jeśli używasz Svcutil.exe do ponownego wygenerowania konfiguracji dla tego przykładu, pamiętaj o zmodyfikowaniu nazw punktów końcowych w konfiguracji klienta w celu dopasowania ich do kodu klienta.

Domyślnie w systemie NetMsmqBindingsą włączone zabezpieczenia transportu. Istnieją dwie istotne właściwości zabezpieczeń transportu MSMQ, MsmqAuthenticationMode a MsmqProtectionLevel. domyślnie tryb uwierzytelniania jest ustawiony na Windows , a poziom ochrony jest ustawiony na Sign. Aby usługa MSMQ zapewniała funkcję uwierzytelniania i podpisywania, musi być częścią domeny, a opcja integracji usługi Active Directory dla usługi MSMQ musi być zainstalowana. Jeśli uruchomisz ten przykład na komputerze, który nie spełnia tych kryteriów, zostanie wyświetlony błąd.

Aby uruchomić przykład na komputerze przyłączonym do grupy roboczej lub bez integracji z usługą Active Directory

  1. Jeśli komputer nie jest częścią domeny lub nie ma zainstalowanej integracji z usługą Active Directory, wyłącz zabezpieczenia transportu, ustawiając tryb uwierzytelniania i poziom ochrony, tak None jak pokazano w następującej przykładowej konfiguracji:

    <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. Wyłączenie zabezpieczeń dla konfiguracji klienta generuje następujące elementy:

    <?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. Usługa dla tego przykładu tworzy powiązanie w pliku OrderProcessorService. Dodaj wiersz kodu po utworzeniu wystąpienia powiązania, aby ustawić tryb zabezpieczeń na None.

    NetMsmqBinding msmqCallbackBinding = new NetMsmqBinding();
    msmqCallbackBinding.Security.Mode = NetMsmqSecurityMode.None;
    
  4. Przed uruchomieniem przykładu upewnij się, że zmienisz konfigurację zarówno na serwerze, jak i na kliencie.

    Uwaga

    Ustawienie security mode wartości jest None równoważne ustawieniu MsmqAuthenticationMode, MsmqProtectionLevel lub Message zabezpieczeń na Nonewartość .