Udostępnij za pośrednictwem


Transakcyjne powiązanie MSMQ

W przykładzie transacted pokazano, jak wykonać komunikację w kolejce przy użyciu kolejkowania komunikatów (MSMQ).

Uwaga

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

W komunikacji w kolejce klient komunikuje się z usługą przy użyciu kolejki. Mówiąc dokładniej, klient wysyła komunikaty do kolejki. 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.

Gdy transakcje są używane do wysyłania i odbierania komunikatów, istnieją faktycznie dwie oddzielne transakcje. Gdy klient wysyła komunikaty w zakresie transakcji, transakcja jest lokalna dla klienta i menedżera kolejek klienta. Gdy usługa odbiera komunikaty w zakresie transakcji, transakcja jest lokalna dla usługi i odbierającego menedżera kolejek. Bardzo ważne jest, aby pamiętać, że klient i usługa nie uczestniczą w tej samej transakcji; zamiast tego używają różnych transakcji podczas wykonywania operacji (takich jak wysyłanie i odbieranie) z kolejką.

W tym przykładzie klient wysyła partię komunikatów do usługi z zakresu transakcji. Komunikaty wysyłane do kolejki są następnie odbierane przez usługę w zakresie transakcji zdefiniowanym przez usługę.

Kontrakt usługi to IOrderProcessor, jak pokazano w poniższym przykładowym kodzie. Interfejs definiuje jednokierunkową usługę, która jest odpowiednia do użycia z kolejkami.

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

Zachowanie usługi definiuje zachowanie operacji z ustawioną wartością TransactionScopeRequiredtrue. Gwarantuje to, że ten sam zakres transakcji, który jest używany do pobierania komunikatu z kolejki, jest używany przez wszystkich menedżerów zasobów, do których uzyskuje dostęp metoda. Gwarantuje również, że jeśli metoda zgłosi wyjątek, komunikat zostanie zwrócony do kolejki. Bez ustawiania tego zachowania operacji w kolejce kanał tworzy transakcję odczytującą komunikat z kolejki i zatwierdza ją automatycznie przed wysłaniem, tak aby w przypadku niepowodzenia operacji komunikat został utracony. Najbardziej typowym scenariuszem jest rejestrowanie operacji usługi w transakcji używanej do odczytywania komunikatu z kolejki, jak pokazano w poniższym kodzie.

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

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 zawiera kod umożliwiający sprawdzenie istnienia kolejki i utworzenie kolejki, jeśli nie istnieje. 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 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();
    }
}

Nazwa kolejki MSMQ jest określona w sekcji aplikacji Ustawienia pliku konfiguracji, jak pokazano w poniższej przykładowej konfiguracji.

<appSettings>
    <add key="queueName" value=".\private$\ServiceModelSamplesTransacted" />
</appSettings>

Uwaga

Nazwa kolejki używa kropki (.) dla komputera lokalnego i separatorów ukośnika odwrotnego w ścieżce podczas tworzenia kolejki przy użyciu polecenia System.Messaging. Punkt końcowy programu Windows Communication Foundation (WCF) używa adresu kolejki ze schematem net.msmq, używa "localhost" do oznaczania komputera lokalnego i używa ukośników w ścieżce.

Klient tworzy zakres transakcji. Komunikacja z kolejką odbywa się w zakresie transakcji, powodując, że jest traktowana jako jednostka niepodzielna, w której wszystkie komunikaty są wysyłane do kolejki lub żaden z komunikatów nie jest wysyłany do kolejki. Transakcja jest zatwierdzana przez wywołanie Complete zakresu transakcji.

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

Aby sprawdzić, czy transakcje działają, zmodyfikuj klienta, komentując zakres transakcji, jak pokazano w poniższym przykładowym kodzie, skompiluj rozwiązanie i uruchom klienta.

//scope.Complete();

Ponieważ transakcja nie została ukończona, komunikaty nie są wysyłane do kolejki.

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. Należy pamiętać, że ponieważ kolejkowanie jest używane, klient i usługa nie muszą być uruchomione w tym samym czasie. Możesz uruchomić klienta, zamknąć go, a następnie uruchomić usługę i nadal odbiera komunikaty.

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

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

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

  2. Jeśli usługa jest uruchomiona jako pierwsza, sprawdzi, czy kolejka jest obecna. Jeśli kolejka nie jest obecna, usługa utworzy je. Możesz najpierw uruchomić usługę, aby utworzyć kolejkę, lub utworzyć jedną za pośrednictwem menedżera kolejki MSMQ. Wykonaj następujące kroki, aby utworzyć kolejkę w systemie Windows 2008.

    1. Otwórz Menedżer serwera w programie Visual Studio 2012.

    2. Rozwiń kartę Funkcje .

    3. Kliknij prawym przyciskiem myszy pozycję Kolejki komunikatów prywatnych, a następnie wybierz pozycję Nowa, Prywatna kolejka.

    4. Zaznacz pole Transakcyjne.

    5. Wprowadź ServiceModelSamplesTransacted jako nazwę nowej kolejki.

  3. 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).

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

Domyślnie w systemie NetMsmqBindingsą włączone zabezpieczenia transportu. Istnieją dwie istotne właściwości zabezpieczeń transportu MSMQ i MsmqAuthenticationModeMsmqProtectionLevel. Domyślnie tryb uwierzytelniania jest ustawiony na Windows wartość , a poziom ochrony jest ustawiony na Signwartość . 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 poniższym przykładowym kodzie konfiguracji.

    <system.serviceModel>
      <services>
        <service name="Microsoft.ServiceModel.Samples.OrderProcessorService"
                 behaviorConfiguration="OrderProcessorServiceBehavior">
          <host>
            <baseAddresses>
              <add baseAddress="http://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 exposed at http://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. 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, MsmqProtectionLeveli Message zabezpieczeń na Nonewartość .