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 Transacted-Beispiel demonstriert, wie man die transaktionale Nachrichtenübermittlung in Warteschlangen mithilfe von Message Queuing (MSMQ) durchführt.
Hinweis
Die Einrichtungsverfahren und Build-Anweisungen für dieses Beispiel befinden sich am Ende dieses Themas.
In einer Warteschlangenkommunikation kommuniziert der Client über eine Warteschlange mit dem Dienst. Genauer gesagt sendet der Client Nachrichten an eine Warteschlange. Der Dienst empfängt Nachrichten aus der Warteschlange. Der Dienst und der Client müssen daher nicht gleichzeitig ausgeführt werden, um mit einer Warteschlange zu kommunizieren.
Wenn Transaktionen zum Senden und Empfangen von Nachrichten verwendet werden, gibt es tatsächlich zwei separate Transaktionen. Wenn der Client Nachrichten im Rahmen einer Transaktion sendet, ist die Transaktion lokal für den Client und den Warteschlangenmanager. Wenn der Dienst Nachrichten im Rahmen der Transaktion empfängt, ist die Transaktion lokal für den Dienst und den empfangenden Warteschlangenmanager. Es ist sehr wichtig zu beachten, dass der Kunde und der Dienst nicht an derselben Transaktion teilnehmen; Stattdessen verwenden sie unterschiedliche Transaktionen, wenn sie ihre Vorgänge (z. B. Senden und Empfangen) mit der Warteschlange ausführen.
In diesem Beispiel sendet der Client einen Batch von Nachrichten aus dem Bereich einer Transaktion an den Dienst. Die an die Warteschlange gesendeten Nachrichten werden dann vom Dienst innerhalb des vom Dienst definierten Transaktionsbereichs empfangen.
Der Dienstvertrag ist IOrderProcessor, wie im folgenden Beispielcode dargestellt. Die Schnittstelle definiert einen unidirektionale Dienst, der für die Verwendung mit Warteschlangen geeignet ist.
[ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples")]
public interface IOrderProcessor
{
[OperationContract(IsOneWay = true)]
void SubmitPurchaseOrder(PurchaseOrder po);
}
Das Dienstverhalten definiert ein Vorgangsverhalten mit TransactionScopeRequired, das auf true festgelegt ist. Dadurch wird sichergestellt, dass derselbe Transaktionsbereich, der zum Abrufen der Nachricht aus der Warteschlange verwendet wird, von allen Ressourcenmanagern verwendet wird, auf die von der Methode zugegriffen wird. Außerdem wird sichergestellt, dass die Nachricht, wenn die Methode eine Ausnahme auslöst, an die Warteschlange zurückgegeben wird. Ohne dieses Vorgangsverhalten festzulegen, erstellt ein in die Warteschlange eingereihter Kanal eine Transaktion, um die Nachricht aus der Warteschlange zu lesen, und führt sie automatisch aus, bevor sie weitergeleitet wird, damit die Nachricht verloren geht, wenn der Vorgang fehlschlägt. Das häufigste Szenario ist, dass Dienstvorgänge sich an der Transaktion beteiligen, mit der die Nachricht aus der Warteschlange gelesen wird, wie im folgenden Code veranschaulicht.
// 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);
}
…
}
Der Dienst wird selbst gehostet. Bei Verwendung des MSMQ-Transports muss die verwendete Warteschlange im Voraus erstellt werden. Dies kann manuell oder über Code erfolgen. In diesem Beispiel enthält der Dienst Code, um das Vorhandensein der Warteschlange zu überprüfen und die Warteschlange zu erstellen, falls sie nicht vorhanden ist. Der Warteschlangenname wird aus der Konfigurationsdatei gelesen. Die Basisadresse wird vom ServiceModel Metadata Utility Tool (Svcutil.exe) verwendet, um den Proxy für den Dienst zu generieren.
// 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();
}
}
Der MSMQ-Warteschlangenname wird in einem AppSettings-Abschnitt der Konfigurationsdatei angegeben, wie in der folgenden Beispielkonfiguration dargestellt.
<appSettings>
<add key="queueName" value=".\private$\ServiceModelSamplesTransacted" />
</appSettings>
Hinweis
Im Warteschlangennamen werden ein Punkt (.) für den lokalen Computer und umgekehrte Schrägstriche als Trennzeichen in der Pfadangabe verwendet, wenn die Warteschlange mithilfe von System.Messaging erstellt wird. Der WCF-Endpunkt (Windows Communication Foundation) verwendet die Warteschlangenadresse mit dem net.msmq-Schema, localhost zur Angabe des lokalen Computers und Schrägstriche in der Pfadangabe.
Der Client erstellt einen Transaktionsbereich. Die Kommunikation mit der Warteschlange findet im Rahmen der Transaktion statt, was dazu führt, dass sie als atome Einheit behandelt wird, in der alle Nachrichten an die Warteschlange gesendet werden oder keines der Nachrichten an die Warteschlange gesendet wird. Für die Transaktion wird ein Commit ausgeführt, indem Complete im Geltungsbereich der Transaktion aufgerufen wird.
// 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();
Um zu überprüfen, ob Transaktionen funktionieren, ändern Sie den Client, indem Sie den Transaktionsbereich kommentieren, wie im folgenden Beispielcode dargestellt, die Lösung neu erstellen und den Client ausführen.
//scope.Complete();
Da die Transaktion nicht abgeschlossen ist, werden die Nachrichten nicht an die Warteschlange gesendet.
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. Drücken Sie die EINGABETASTE in den einzelnen Konsolenfenstern, um den Dienst und den Client zu schließen. Beachten Sie, dass aufgrund der Verwendung einer Warteschlange der Client und der Dienst nicht gleichzeitig laufen müssen. Sie können den Client ausführen, ihn herunterfahren und dann den Dienst starten und die Nachrichten weiterhin empfangen.
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
So können Sie das Beispiel einrichten, erstellen und ausführen
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.
Führen Sie das Beispiel in einer Einzel- oder computerübergreifenden Konfiguration aus, indem Sie die Anweisungen unter Ausführen der Windows Communication Foundation-Beispiele befolgen.
Standardmäßig wird mit NetMsmqBinding die Transportsicherheit aktiviert. Es gibt zwei relevante Eigenschaften für die MSMQ-Transportsicherheit: MsmqAuthenticationMode und MsmqProtectionLevel. Standardmäßig ist der Authentifizierungsmodus auf Windows gesetzt und die Schutzebene auf Sign. Damit MSMQ die Authentifizierungs- und Signaturfunktion bereitstellt, muss sie Teil einer Domäne sein, und die Active Directory-Integrationsoption für MSMQ muss installiert werden. Wenn Sie dieses Beispiel auf einem Computer ausführen, der diese Kriterien nicht erfüllt, wird eine Fehlermeldung angezeigt.
So führen Sie das Beispiel auf einem Computer aus, der mit einer Arbeitsgruppe oder ohne Active Directory-Integration verbunden ist
Wenn Ihr Computer nicht Teil einer Domäne ist oder keine Active Directory-Integration installiert ist, deaktivieren Sie die Transportsicherheit, indem Sie den Authentifizierungsmodus und die Schutzstufe wie
Noneim folgenden Beispielkonfigurationscode gezeigt festlegen.<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>Stellen Sie sicher, dass Sie die Konfiguration auf dem Server und dem Client ändern, bevor Sie das Beispiel ausführen.
Hinweis
Die Einstellung
security modeaufNoneentspricht dem Festlegen von MsmqAuthenticationMode, MsmqProtectionLevel undMessageSicherheit aufNone.