Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Das MessageCorrelation-Beispiel veranschaulicht, wie eine Message Queuing (MSMQ)-Anwendung eine MSMQ-Nachricht an einen Wcf-Dienst (Windows Communication Foundation) senden kann und wie Nachrichten in einem Anforderungs-/Antwortszenario zwischen Absender- und Empfängeranwendungen korreliert werden können. In diesem Beispiel wird die msmqIntegrationBinding-Bindung verwendet. Der Dienst in diesem Fall ist eine selbst gehostete Konsolenanwendung, mit der Sie den Dienst beobachten können, der Nachrichten aus der Warteschlange empfängt. k
Der Dienst verarbeitet die vom Absender empfangene Nachricht und sendet eine Antwortnachricht an den Absender zurück. Der Absender korreliert die Antwort, die er auf die ursprünglich gesendete Anfrage erhalten hat. Die Eigenschaften MessageID und CorrelationID der Nachricht werden verwendet, um die Anforderungs- und Antwortnachrichten zu korrelieren.
Der IOrderProcessor-Dienstvertrag definiert einen unidirektionalen Dienstvorgang, der für die Verwendung mit Warteschlangen geeignet ist. Eine MSMQ-Nachricht verfügt nicht über einen Aktionsheader, sodass es nicht möglich ist, unterschiedliche MSMQ-Nachrichten automatisch Vorgangsverträge zuzuordnen. Daher kann es in diesem Fall nur einen Betriebsvertrag geben. Wenn Sie weitere Vorgangsverträge im Dienst definieren möchten, muss die Anwendung Informationen darüber bereitstellen, welche Kopfzeile in der MSMQ-Nachricht (z. B. die Bezeichnung oder CorrelationID) verwendet werden kann, um zu entscheiden, welcher Vorgangsvertrag ausgeführt werden soll.
Die MSMQ-Nachricht enthält auch keine Informationen darüber, welche Kopfzeilen den verschiedenen Parametern des Vorgangsvertrags zugeordnet sind. Daher kann es nur einen Parameter im Vorgangsvertrag geben. Der Parameter ist vom Typ MsmqMessage<T>, der die zugrunde liegende MSMQ-Nachricht enthält. Der Typ "T" in der MsmqMessage<T> Klasse stellt die Daten dar, die in den MSMQ-Nachrichtentext serialisiert werden. In diesem Beispiel wird der PurchaseOrder-Typ zum MSMQ-Nachrichtentext serialisiert.
[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 dessen Status im Dienstkonsolenfenster an. 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.
PurchaseOrder enthält die Bestelldetails, die vom Dienst verarbeitet werden müssen.
// 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 fulfillment.
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 Client OrderResponseClient , um die MSMQ-Nachricht an die Warteschlange zu senden. Da es sich bei der Anwendung, die die Nachricht empfängt und verarbeitet, um eine MSMQ-Anwendung und nicht um eine WCF-Anwendung handelt, gibt es keinen impliziten Dienstvertrag zwischen den beiden Anwendungen. Daher können wir in diesem Szenario keinen Proxy mit dem Svcutil.exe Tool erstellen.
Der benutzerdefinierte Proxy ist im Wesentlichen für alle WCF-Anwendungen identisch, die die msmqIntegrationBinding Bindung zum Senden von Nachrichten verwenden. Im Gegensatz zu anderen Proxys enthält sie keine Reihe von Dienstvorgängen. Es handelt sich nur um einen Nachrichtensendevorgang.
[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 wird selbst gehostet. Bei Verwendung des MSMQ-Integrationstransports muss die verwendete Warteschlange im Voraus erstellt werden. Dies kann manuell oder über Code erfolgen. In diesem Beispiel enthält System.Messaging der Dienst Code, um das Vorhandensein der Warteschlange zu überprüfen und sie bei Bedarf zu erstellen. Der Warteschlangenname wird aus der Konfigurationsdatei gelesen.
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" der Konfigurationsdatei angegeben. Die Client- und Dienstendpunkte werden im Abschnitt "system.serviceModel" der Konfigurationsdatei definiert. Beide geben die msmqIntegrationBinding Bindung an.
<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 dauerhafte und transaktionsfähige Nachricht an die Warteschlange zu senden. Der Textkörper der Nachricht enthält die Bestellung.
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.
Hinweis
Im Warteschlangennamen wird ein Punkt (.) für den lokalen Computer verwendet, und in der Pfadangabe werden umgekehrte Schrägstriche als Trennzeichen verwendet. Die WCF-Endpunktadresse gibt ein msmq.formatname-Schema an und verwendet "localhost" für den lokalen Computer. Im URI steht hinter msmq.formatname ein korrekt aufgebauter Formatname gemäß MSMQ-Richtlinien.
<appSettings>
<add key=" orderResponseQueueName" value=".\private$\Orders" />
</appSettings>
Die Clientanwendung speichert die messageID Bestellanforderungsnachricht, die sie an den Dienst sendet, und wartet auf eine Antwort vom Dienst. Sobald eine Antwort in der Warteschlange eingetroffen ist, ordnet der Client die Antwort der Bestellnachricht zu, die er gesendet hat, mithilfe der correlationID-Eigenschaft der Nachricht, welche die messageID der ursprünglich an den Dienst gesendeten Bestellnachricht enthält.
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 in den Dienst- als auch in den Clientkonsolenfenstern angezeigt. Sie können sehen, dass der Dienst Nachrichten vom Client empfängt und eine Antwort an den Client sendet. Der Client zeigt die antwort an, die vom Dienst empfangen wurde. Drücken Sie in jedem Konsolenfenster die EINGABETASTE, um den Dienst und den Client zu beenden.
Hinweis
Für dieses Beispiel ist die Installation von Message Queuing (MSMQ) erforderlich. Weitere Informationen finden Sie in den MSMQ-Installationsanweisungen im Abschnitt "Siehe auch".
Einrichten, Erstellen und Ausführen des Beispiels
Stellen Sie sicher, dass Sie das One-Time Setup-Verfahren für die Windows Communication Foundation-Beispieleausgeführt haben.
Wenn der Dienst zuerst ausgeführt wird, wird überprüft, ob die Warteschlange vorhanden ist. Wenn die Warteschlange nicht vorhanden ist, erstellt der Dienst eine. Sie können den Dienst zuerst ausführen, um die Warteschlange zu erstellen, oder Sie können einen über den MSMQ-Warteschlangen-Manager erstellen. Führen Sie die folgenden Schritte aus, um eine Warteschlange in Windows 2008 zu erstellen.
Öffnen Sie den Server-Manager in Visual Studio 2012.
Erweitern Sie die Registerkarte Features.
Klicken Sie mit der rechten Maustaste auf Private Meldungswarteschlangen, und klicken Sie anschließend auf Neu und Private Warteschlange.
Aktivieren Sie das Kontrollkästchen Transaktional.
Geben Sie
ServiceModelSamplesTransactedals Namen der neuen Warteschlange ein.
Um die C#- oder Visual Basic .NET-Edition der Lösung zu erstellen, befolgen Sie die Anweisungen in Building the Windows Communication Foundation Samples.
Um das Beispiel in einer Einzelrechnerkonfiguration auszuführen, folgen Sie den Anweisungen unter Ausführen der Windows Communication Foundation-Beispiele.
Führen Sie das Beispiel auf mehreren Computern aus
Kopieren Sie die Dienstprogrammdateien aus dem Ordner \service\bin\ unter dem sprachspezifischen Ordner auf den Dienstcomputer.
Kopieren Sie die Clientprogrammdateien aus dem Ordner "\client\bin\" unter dem sprachspezifischen Ordner auf den Clientcomputer.
Ändern Sie in der datei Client.exe.config den OrderQueueName so, dass anstelle von "." der Dienstcomputername angegeben wird.
Ändern Sie in der datei Service.exe.config die Clientendpunktadresse, um den Namen des Clientcomputers anstelle von "." anzugeben.
Starten Sie auf dem Dienstcomputer Service.exe an einer Eingabeaufforderung.
Starten Sie auf dem Clientcomputer Client.exe an einer Eingabeaufforderung.