NachrichtenkorrelationMessage Correlation

Dieses Beispiel zeigt, wie eine MSMQ-Anwendung (Message Queuing) eine MSMQ-Nachricht an einen Windows Communication Foundation (WCF)Windows Communication Foundation (WCF)-Dienst senden kann und wie Nachrichten zwischen Sender- und Empfängeranwendungen in einem Anforderungs/Antwort-Szenario korreliert werden können.This sample demonstrates how a Message Queuing (MSMQ) application can send an MSMQ message to a Windows Communication Foundation (WCF)Windows Communication Foundation (WCF) service and how messages can be correlated between sender and receiver applications in a request/response scenario. In diesem Beispiel wird die msmqIntegrationBinding-Bindung verwendet.This sample uses the msmqIntegrationBinding binding. Der Dienst ist in diesem Fall eine selbst gehostete Konsolenanwendung, sodass Sie den Dienst beobachten können, der Nachrichten in Warteschlangen empfängt.The service in this case is a self-hosted console application to allow you to observe the service that receives queued messages. ck

Der Dienst verarbeitet die vom Sender empfangene Nachricht und sendet eine Antwortnachricht zurück an den Sender.The service processes the message received from the sender and sends a response message back to the sender. Der Sender korreliert die Antwort, die er auf die ursprünglich gesendete Anforderung empfangen hat.The sender correlates the response it received to the request it sent originally. Die MessageID-Eigenschaft und die CorrelationID-Eigenschaft der Nachricht werden zum Korrelieren der Anforderungs- und Antwortnachrichten verwendet.The MessageID and CorrelationID properties of the message are used to correlate the request and response messages.

Der IOrderProcessor-Dienstvertrag definiert einen unidirektionalen Dienstvorgang, der für die Verwendung mit Warteschlangen geeignet ist.The IOrderProcessor service contract defines a one-way service operation that is suitable for use with queuing. Eine MSMQ-Nachricht verfügt über keinen Aktionsheader, d h. es ist nicht möglich, verschiedene MSMQ-Nachrichten Vorgangsverträgen automatisch zuzuordnen.An MSMQ message does not have an Action header, so it is not possible to map different MSMQ messages to operation contracts automatically. Deshalb kann es in diesem Fall nur einen Vorgangsvertrag geben.Therefore, there can be only one operation contract in this case. Wenn Sie mehrere Vorgangsverträge in dem Dienst definieren möchten, muss die Anwendung Informationen darüber bereitstellen, anhand welchen Headers in der MSMQ-Nachricht (z. B. die Bezeichnung oder die CorrelationID) entschieden werden kann, welcher Vorgangsvertrag verteilt werden soll.If you want to define more operation contracts in the service, the application must provide information as to which header in the MSMQ message (for example, the label, or correlationID) can be used to decide which operation contract to dispatch. Dies wird dargestellt, der benutzerdefinierter Demux.This is demonstrated in the Custom Demux.

Die MSMQ-Nachricht enthält auch keine Informationen darüber, welche Header den verschiedenen Parametern des Vorgangsvertrags zugeordnet sind.The MSMQ message also does not contain information as to which headers are mapped to the different parameters of the operation contract. Daher kann sich im Vorgangsvertrag nur ein Parameter befinden.Therefore, there can be only one parameter in the operation contract. Der Parameter ist vom Typ , System.ServiceModel.MSMQIntegration.MsmqMessage die zugrunde liegende MSMQ-Nachricht enthält.The parameter is of type , System.ServiceModel.MSMQIntegration.MsmqMessage which contains the underlying MSMQ message. Der Typ "T" in der MsmqMessage<T>-Klasse stellt die Daten dar, die in den MSMQ-Nachrichtentext serialisiert sind.The type "T" in the MsmqMessage<T> class represents the data that is serialized into the MSMQ message body. In diesem Beispiel wird der PurchaseOrder-Typ zum MSMQ-Nachrichtentext serialisiert.In this sample, the PurchaseOrder type is serialized into the MSMQ message body.

[ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples")]  
[ServiceKnownType(typeof(PurchaseOrder))]  
public interface IOrderProcessor  
{  
    [OperationContract(IsOneWay = true, Action = "*")]  
    void SubmitPurchaseOrder(MsmqMessage<PurchaseOrder> msg);  
}  

Der Dienstvorgang verarbeitet die Bestellung und zeigt den Inhalt der Bestellung und deren Status im Dienstkonsolenfenster an.The service operation processes the purchase order and displays the contents of the purchase order and its status in the service console window. Das OperationBehaviorAttribute konfiguriert, dass der Vorgang in eine Transaktion mit der Warteschlange eingetragen wird und dass die Transaktion als abgeschlossen gekennzeichnet wird, wenn der Vorgang zurückkehrt.The OperationBehaviorAttribute configures the operation to enlist in a transaction with the queue and to mark the transaction complete when the operation returns. Die PurchaseOrder enthält die Bestellungsdetails, die vom Dienst verarbeitet werden müssen.The PurchaseOrder contains the order details that must be processed by the service.

// Service class that implements the service contract.  
public class OrderProcessorService : IOrderProcessor  
{  
   [OperationBehavior(TransactionScopeRequired = true,   
          TransactionAutoComplete = true)]  
   public void SubmitPurchaseOrder(MsmqMessage<PurchaseOrder> ordermsg)  
   {  
       PurchaseOrder po = (PurchaseOrder)ordermsg.Body;  
       Random statusIndexer = new Random();  
       po.Status = PurchaseOrder.OrderStates[statusIndexer.Next(3)];  
       Console.WriteLine("Processing {0} ", po);  
       //Send a response to the client that the order has been received   
         and is pending fullfillment.   
       SendResponse(ordermsg);  
    }  

    private void SendResponse(MsmqMessage<PurchaseOrder> ordermsg)  
    {  
        OrderResponseClient client = new OrderResponseClient("OrderResponseEndpoint");  

        //Set the correlation ID such that the client can correlate the response to the order.  
        MsmqMessage<PurchaseOrder> orderResponsemsg = new MsmqMessage<PurchaseOrder>(ordermsg.Body);  
        orderResponsemsg.CorrelationId = ordermsg.Id;  
        using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))  
        {  
            client.SendOrderResponse(orderResponsemsg);  
            scope.Complete();  
        }  

        client.Close();  
    }  
}  

Der Dienst verwendet einen benutzerdefinierten OrderResponseClient-Client zum Senden der MSMQ-Nachricht an die Warteschlange.The service uses a custom client OrderResponseClient to send the MSMQ message to the queue. Da die Anwendung, die die Nachricht empfängt und verarbeitet, keine WCFWCF- sondern eine MSMQ-Anwendung ist, besteht zwischen den beiden Anwendungen kein implizierter Dienstvertrag.Because the application that receives and processes the message is an MSMQ application and not a WCFWCF application, there is no implicit service contract between the two applications. Deshalb kann in diesem Szenario kein Proxy mit dem Tool Svcutil.exe erstellt werden.So we cannot create a proxy using the Svcutil.exe tool in this scenario.

Der benutzerdefinierte Proxy ist im Wesentlichen bei allen WCFWCF-Anwendungen gleich, die die msmqIntegrationBinding-Bindung zum Senden von Nachrichten verwenden.The custom proxy is essentially the same for all WCFWCF applications that use the msmqIntegrationBinding binding to send messages. Im Gegensatz zu anderen Proxys enthält dieser keinen Bereich von Dienstvorgängen.Unlike other proxies, it does not include a range of service operations. Es ist nur ein Sende-Nachricht-Vorgang.It is a submit message operation only.

[System.ServiceModel.ServiceContractAttribute(Namespace = "http://Microsoft.ServiceModel.Samples")]  
public interface IOrderResponse  
{  

    [System.ServiceModel.OperationContractAttribute(IsOneWay = true, Action = "*")]  
    void SendOrderResponse(MsmqMessage<PurchaseOrder> msg);  
}  

public partial class OrderResponseClient : System.ServiceModel.ClientBase<IOrderResponse>, IOrderResponse  
{  

    public OrderResponseClient()  
    { }  

    public OrderResponseClient(string configurationName)  
        : base(configurationName)  
    { }  

    public OrderResponseClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress address)  
        : base(binding, address)  
    { }  

    public void SendOrderResponse(MsmqMessage<PurchaseOrder> msg)  
    {  
        base.Channel.SendOrderResponse(msg);  
    }  
}  

Der Dienst ist selbst gehostet.The service is self hosted. Bei Verwendung des MSMQ-Integrationstransports muss die Warteschlange im Voraus erstellt werden.When using the MSMQ integration transport, the queue used must be created in advance. Dies kann manuell erfolgen oder mithilfe eines Codes.This can be done manually or through code. In diesem Beispiel enthält der Dienst System.Messaging-Code, um zu überprüfen, ob die Warteschlange bereits vorhanden ist, und um sie andernfalls zu erstellen.In this sample, the service contains System.Messaging code to check for the existence of the queue and create it if necessary. Der Warteschlangenname wird aus der Konfigurationsdatei gelesen.The queue name is read from the configuration file.

public static void Main()  
{  
       // Get the MSMQ queue name from application settings in configuration.  
      string queueName =   
                ConfigurationManager.AppSettings["orderQueueName"];  
      // 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)))  
     {  
            serviceHost.Open();  
            // The service can now be accessed.  
            Console.WriteLine("The service is ready.");  
            Console.WriteLine("Press <ENTER> to terminate service.");  
            Console.ReadLine();  
            // Close the ServiceHost to shutdown the service.  
            serviceHost.Close();  
      }  
}  

Die MSMQ-Warteschlange, an die die Bestellanforderungen gesendet werden, wird im Abschnitt "appSettings" in der Konfigurationsdatei angegeben.The MSMQ queue to which the order requests are sent is specified in the appSettings section of the configuration file. Die Client- und Dienstendpunkte werden im Abschnitt "system.serviceModel" der Konfigurationsdatei definiert.The client and service endpoints are defined in the system.serviceModel section of the configuration file. Beide geben die msmqIntegrationbinding-Bindung an.Both specify the msmqIntegrationbinding binding.

<appSettings>  
  <add key="orderQueueName" value=".\private$\Orders" />  
</appSettings>  

<system.serviceModel>  
  <client>  
    <endpoint    name="OrderResponseEndpoint"   
              address="msmq.formatname:DIRECT=OS:.\private$\OrderResponse"  
              binding="msmqIntegrationBinding"  
              bindingConfiguration="OrderProcessorBinding"   
              contract="Microsoft.ServiceModel.Samples.IOrderResponse">  
    </endpoint>  
  </client>  

  <services>  
    <service   
      name="Microsoft.ServiceModel.Samples.OrderProcessorService">  
      <endpoint address="msmq.formatname:DIRECT=OS:.\private$\Orders"  
                            binding="msmqIntegrationBinding"  
                bindingConfiguration="OrderProcessorBinding"   
                contract="Microsoft.ServiceModel.Samples.IOrderProcessor">  
      </endpoint>  
    </service>  
  </services>  

  <bindings>  
    <msmqIntegrationBinding>  
      <binding name="OrderProcessorBinding" >  
        <security mode="None" />  
      </binding>  
    </msmqIntegrationBinding>  
  </bindings>  

</system.serviceModel>  

Die Clientanwendung verwendet System.Messaging, um eine permanente und Transaktionsnachricht an die Warteschlange zu senden.The client application uses System.Messaging to send a durable and transactional message to the queue. Der Text der Nachricht enthält die Bestellung.The message's body contains the purchase order.

static void PlaceOrder()  
{  
    //Connect to the queue  
    MessageQueue orderQueue =   
            new MessageQueue(  
                    ConfigurationManager.AppSettings["orderQueueName"])   
    // 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;  

    Message msg = new Message();  
    msg.UseDeadLetterQueue = true;  
    msg.Body = po;  

    //Create a transaction scope.  
    using (TransactionScope scope = new      
     TransactionScope(TransactionScopeOption.Required))  
    {  
        // Submit the purchase order.  
        orderQueue.Send(msg, MessageQueueTransactionType.Automatic);  
        // Complete the transaction.  
        scope.Complete();  
    }  
    //Save the messageID for order response correlation.  
    orderMessageID = msg.Id;  
    Console.WriteLine("Placed the order, waiting for response...");  
}  

Die MSMQ-Warteschlange, aus der die Bestellantworten empfangen werden, wird in einem appSettings-Abschnitt der Konfigurationsdatei angegeben, wie in der folgenden Beispielkonfiguration gezeigt.The MSMQ queue from which the order responses are received is specified in an appSettings section of the configuration file, as shown in the following sample configuration.

Hinweis

Im Warteschlangennamen wird ein Punkt (.) für den lokalen Computer verwendet, und in der Pfadangabe werden umgekehrte Schrägstriche als Trennzeichen verwendet.The queue name uses a dot (.) for the local computer and backslash separators in its path. Die WCFWCF-Endpunktadresse gibt ein msmq.formatname-Schema an, und für den lokalen Computer wird localhost verwendet.The WCFWCF endpoint address specifies a msmq.formatname scheme, and uses "localhost" for the local computer. Im URI steht hinter msmq.formatname ein korrekt aufgebauter Formatname gemäß MSMQ-Richtlinien.A properly formed format name follows msmq.formatname in the URI according to MSMQ guidelines.

<appSettings>  
    <add key=" orderResponseQueueName" value=".\private$\Orders" />  
</appSettings>  

Die Clientanwendung speichert die messageID der Bestellungsanforderungsnachricht, die sie an den Dienst sendet, und wartet auf eine Antwort vom Dienst.The client application saves the messageID of the order request message that it sends to the service and waits for a response from the service. Sobald in der Warteschlange eine Antwort eingeht, korreliert der Client diese mit der Bestellnachricht, die er mit der correlationID-Eigenschaft der Nachricht gesendet hat, die die messageID der Bestellnachricht enthält, die der Dienst ursprünglich an den Dienst gesendet hat.Once a response arrives in the queue the client correlates it with the order message it sent using the correlationID property of the message, which contains the messageID of the order message that the client sent to the service originally.

static void DisplayOrderStatus()  
{  
    MessageQueue orderResponseQueue = new   
     MessageQueue(ConfigurationManager.AppSettings              
                  ["orderResponseQueueName"]);  
    //Create a transaction scope.  
    bool responseReceived = false;  
    orderResponseQueue.MessageReadPropertyFilter.CorrelationId = true;  
    while (!responseReceived)  
    {  
       Message responseMsg;  
       using (TransactionScope scope2 = new    
         TransactionScope(TransactionScopeOption.Required))  
       {  
          //Receive the Order Response message.  
          responseMsg =   
              orderResponseQueue.Receive  
                   (MessageQueueTransactionType.Automatic);  
          scope2.Complete();  
     }  
     responseMsg.Formatter = new   
     System.Messaging.XmlMessageFormatter(new Type[] {   
         typeof(PurchaseOrder) });  
     PurchaseOrder responsepo = (PurchaseOrder)responseMsg.Body;  
    //Check if the response is for the order placed.  
    if (orderMessageID == responseMsg.CorrelationId)  
    {  
       responseReceived = true;  
       Console.WriteLine("Status of current Order: OrderID-{0},Order   
            Status-{1}", responsepo.PONumber, responsepo.Status);  
    }  
    else  
    {  
       Console.WriteLine("Status of previous Order: OrderID-{0},Order    
            Status-{1}", responsepo.PONumber, responsepo.Status);  
    }  
  }  
}  

Wenn Sie das Beispiel ausführen, werden die Client- und Dienstaktivitäten sowohl im Dienst- als auch im Clientkonsolenfenster angezeigt.When you run the sample, the client and service activities are displayed in both the service and client console windows. Sie können sehen, dass der Dienst Nachrichten vom Client empfängt und eine Antwort an den Client zurücksendet.You can see the service receive messages from the client and sends a response back to the client. Der Client zeigt die vom Dienst empfangene Antwort an.The client displays the response received from the service. Drücken Sie die EINGABETASTE in den einzelnen Konsolenfenstern, um den Dienst und den Client zu schließen.Press ENTER in each console window to shut down the service and client.

Hinweis

Dieses Beispiel erfordert die Installation von Message Queuing (MSMQ).This sample requires the installation of Message Queuing (MSMQ). Informationen dazu finden Sie in den MSMQ-Installationsanleitungen im Abschnitt "Siehe auch".See the MSMQ installation instructions in the See Also section.

So richten Sie das Beispiel ein, erstellen es und führen es ausTo setup, build, and run the sample

  1. Stellen Sie sicher, dass Sie ausgeführt haben die Setupprozedur für die Windows Communication Foundation-Beispiele zum einmaligen.Ensure that you have performed the One-Time Setup Procedure for the Windows Communication Foundation Samples.

  2. Wenn der Dienst zuerst ausgeführt wird, wird überprüft, ob die Warteschlange vorhanden ist.If the service is run first, it will check to ensure that the queue is present. Ist die Warteschlange nicht vorhanden, wird sie vom Dienst erstellt.If the queue is not present, the service will create one. Sie können zuerst den Dienst ausführen, um die Warteschlange zu erstellen, oder Sie können sie über den MSMQ-Warteschlangen-Manager erstellen.You can run the service first to create the queue, or you can create one via the MSMQ Queue Manager. Führen Sie zum Erstellen einer Warteschlange in Windows 2008 die folgenden Schritte aus:Follow these steps to create a queue in Windows 2008.

    1. Öffnen Sie Server-Manager in Visual Studio 2012Visual Studio 2012.Open Server Manager in Visual Studio 2012Visual Studio 2012.

    2. Erweitern Sie die Funktionen Registerkarte.Expand the Features tab.

    3. Mit der rechten Maustaste Private Meldungswarteschlangen, und wählen Sie neu, Private Warteschlange.Right-click Private Message Queues, and select New, Private Queue.

    4. Überprüfen Sie die transaktional Feld.Check the Transactional box.

    5. Geben Sie ServiceModelSamplesTransacted als Namen für die neue Warteschlange.Enter ServiceModelSamplesTransacted as the name of the new queue.

  3. Um die C#- oder Visual Basic .NET-Edition der Projektmappe zu erstellen, befolgen Sie die unter Building the Windows Communication Foundation Samplesaufgeführten Anweisungen.To build the C# or Visual Basic .NET edition of the solution, follow the instructions in Building the Windows Communication Foundation Samples.

  4. Führen Sie zum Ausführen des Beispiels in einer einzelnen Computerkonfiguration die Anweisungen im Ausführen der Windows Communication Foundation-Beispiele.To run the sample in a single-computer configuration, follow the instructions in Running the Windows Communication Foundation Samples.

So führen Sie das Beispiel computerübergreifend ausTo run the sample across computers

  1. Kopieren Sie die Dienstprogrammdateien aus dem Ordner \service\bin\ (unterhalb des sprachspezifischen Ordners) auf den Dienstcomputer.Copy the service program files from the \service\bin\ folder, under the language-specific folder, to the service computer.

  2. Kopieren Sie die Clientprogrammdateien aus dem Ordner \client\bin\ (unterhalb des sprachspezifischen Ordners) auf den Clientcomputer.Copy the client program files from the \client\bin\ folder, under the language-specific folder, to the client computer.

  3. Ändern Sie in der Datei Client.exe.config den Wert von orderQueueName, und geben Sie anstelle von "." den Namen des Dienstcomputers an.In the Client.exe.config file, change the orderQueueName to specify the service computer name instead of ".".

  4. Ändern Sie in der Datei Service.exe.config die Clientendpunktadresse, und geben Sie anstelle von "." den Namen des Clientcomputers an.In the Service.exe.config file, change the client endpoint address to specify the client computer name instead of ".".

  5. Starten Sie auf dem Dienstcomputer Service.exe an einer Eingabeaufforderung.On the service computer, launch Service.exe from a command prompt.

  6. Starten Sie auf dem Clientcomputer Client.exe an einer Eingabeaufforderung.On the client computer, launch Client.exe from a command prompt.

Wichtig

Die Beispiele sind möglicherweise bereits auf dem Computer installiert.The samples may already be installed on your computer. Suchen Sie nach dem folgenden Verzeichnis (Standardverzeichnis), bevor Sie fortfahren.Check for the following (default) directory before continuing.

<InstallDrive>:\WF_WCF_Samples

Wenn dieses Verzeichnis nicht vorhanden ist, rufen Sie Windows Communication Foundation (WCF) and Windows Workflow Foundation (WF) Samples for .NET Framework 4 auf, um alle Windows Communication Foundation (WCF)Windows Communication Foundation (WCF) - und WFWF -Beispiele herunterzuladen.If this directory does not exist, go to Windows Communication Foundation (WCF) and Windows Workflow Foundation (WF) Samples for .NET Framework 4 to download all Windows Communication Foundation (WCF)Windows Communication Foundation (WCF) and WFWF samples. Dieses Beispiel befindet sich im folgenden Verzeichnis.This sample is located in the following directory.

<InstallDrive>:\WF_WCF_Samples\WCF\Basic\Binding\MSMQIntegration\MessageCorrelation

Siehe auchSee Also

Queuing in WCFQueuing in WCF
Message QueuingMessage Queuing