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 DeadLetter-Beispiel veranschaulicht, wie Nachrichten behandelt und verarbeitet werden, die nicht zugestellt werden konnten. Dieses Beispiel basiert auf dem Beispiel Abgewickelte MSMQ-Bindung. In diesem Beispiel wird die netMsmqBinding Bindung verwendet. Der Dienst ist eine selbst gehostete Konsolenanwendung, mit der Sie beobachten können, wie der Dienst Nachrichten aus der Warteschlange empfängt.
Hinweis
Die Einrichtungsverfahren und Build-Anweisungen für dieses Beispiel befinden sich am Ende dieses Themas.
Hinweis
In diesem Beispiel werden die einzelnen Anwendungswarteschlangen für unzustellbare Nachrichten veranschaulicht, die nur in Windows Vista verfügbar sind. Das Beispiel kann geändert werden, um die standardmäßigen systemweiten Warteschlangen für MSMQ 3.0 unter Windows Server 2003 und Windows XP zu verwenden.
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.
Da die Kommunikation über Warteschlangen zu einer gewissen Verzögerung führen kann, können Sie der Nachricht eine Gültigkeitsdauer zuweisen, um sicherzustellen, dass die Nachricht nach Ablauf der Gültigkeit nicht mehr an die Anwendung gesendet wird. Es gibt auch Fälle, in denen eine Anwendung darüber informiert werden muss, ob die Zustellung einer Nachricht fehlgeschlagen ist. In derartigen Fällen, wenn beispielsweise die Gültigkeitsdauer der Nachricht abgelaufen ist, oder wenn die Nachricht nicht zugestellt werden konnte, werden die Nachrichten in der Warteschlange für unzustellbare Nachrichten abgelegt. Die sendende Anwendung kann dann die Nachrichten in der Dead-Letter-Queue lesen und Korrekturmaßnahmen ergreifen, die von keiner Aktion bis hin zur Korrektur der Gründe für die fehlgeschlagene Zustellung und das erneute Senden der Nachricht reichen.
Die Warteschlange für unzustellbare Nachrichten in der NetMsmqBinding-Bindung wird in den folgenden Eigenschaften ausgedrückt:
DeadLetterQueue-Eigenschaft, um die vom Client benötigte Art der Warteschlange für unzustellbare Nachrichten auszudrücken. Diese Aufzählung weist die folgenden Werte auf:
None: Für den Client ist keine Warteschlange für unzustellbare Nachrichten erforderlich.System: Die Systemwarteschlange für unzustellbare Nachrichten wird verwendet, um unzustellbare Nachrichten zu speichern. Die Systemwarteschlange für unzustellbare Nachrichten wird von allen Anwendungen verwendet, die auf dem Computer ausgeführt werden.Custom: Die in der CustomDeadLetterQueue-Eigenschaft angegebene benutzerdefinierte Warteschlange für unzustellbare Nachrichten wird verwendet, um unzustellbare Nachrichten zu speichern. Dieses Feature ist nur unter Windows Vista verfügbar. Dies wird verwendet, wenn die Anwendung eine eigene Warteschlange für inaktive Buchstaben verwenden muss, anstatt sie mit anderen Anwendungen zu teilen, die auf demselben Computer ausgeführt werden.CustomDeadLetterQueue-Eigenschaft, um die spezifische Warteschlange für unzustellbare Nachrichten anzugeben. Dies ist nur in Windows Vista verfügbar.
In diesem Beispiel sendet der Client einen Batch von Nachrichten aus dem Bereich einer Transaktion an den Dienst und gibt einen willkürlich niedrigen Wert für "Time-to-Live" für diese Nachrichten an (ca. 2 Sekunden). Der Client gibt auch eine benutzerdefinierte Warteschlange für unzustellbare Nachrichten an, in der abgelaufene Nachrichten abgelegt werden.
Die Clientanwendung kann die Nachrichten in der Dead-Letter-Warteschlange lesen und entweder versuchen, die Nachricht erneut zu senden, oder den Fehler beheben, der dazu führte, dass die ursprüngliche Nachricht in die Dead-Letter-Warteschlange platziert wurde, und dann die Nachricht senden. Im Beispiel zeigt der Client eine Fehlermeldung an.
Der Dienstvertrag ist IOrderProcessor, wie im folgenden Beispielcode dargestellt.
[ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples")]
public interface IOrderProcessor
{
[OperationContract(IsOneWay = true)]
void SubmitPurchaseOrder(PurchaseOrder po);
}
Der Dienstcode im Beispiel entspricht dem im Beispiel Abgewickelte MSMQ-Bindung.
Die Kommunikation mit dem Dienst erfolgt im Rahmen einer Transaktion. Der Dienst liest Nachrichten aus der Warteschlange, führt den Vorgang aus und zeigt dann die Ergebnisse des Vorgangs an. Die Anwendung erstellt auch eine Warteschlange für unzustellbare Nachrichten.
//The service contract is defined in generatedClient.cs, generated from the service by the svcutil tool.
//Client implementation code.
class Client
{
static void Main()
{
// Get MSMQ queue name from app settings in configuration
string deadLetterQueueName = ConfigurationManager.AppSettings["deadLetterQueueName"];
// Create the transacted MSMQ queue for storing dead message if necessary.
if (!MessageQueue.Exists(deadLetterQueueName))
MessageQueue.Create(deadLetterQueueName, true);
// Create a proxy with given client endpoint configuration
OrderProcessorClient client = new OrderProcessorClient("OrderProcessorEndpoint");
// 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();
}
client.Close();
Console.WriteLine();
Console.WriteLine("Press <ENTER> to terminate client.");
Console.ReadLine();
}
}
Die Konfiguration des Clients gibt eine kurze Zeitspanne an, während derer die Nachricht den Dienst erreichen muss. Wenn die Nachricht nicht innerhalb der angegebenen Dauer übertragen werden kann, verfällt sie und wird in die Dead-Letter-Warteschlange verschoben.
Hinweis
Es ist möglich, dass der Client die Nachricht innerhalb der angegebenen Zeit an die Dienstwarteschlange weitergibt. Um sicherzustellen, dass Sie die Ausführung des Diensts für unzustellbare Nachrichten beobachten können, sollten Sie den Client vor dem Start des Diensts ausführen. Die Nachricht überschreitet das Zeitlimit und wird an den Dienst für unzustellbaren Nachrichten übermittelt.
Die Anwendung muss definieren, welche der Warteschlangen als Warteschlange für unzustellbare Nachrichten verwendet werden soll. Wenn keine Warteschlange angegeben wird, wird die systemweite Standardtransaktionswarteschlange für unzustellbare Nachrichten verwendet. In diesem Beispiel gibt die Clientanwendung ihre eigene Anwendungswarteschlange für unzustellbare Nachrichten an.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<!-- use appSetting to configure MSMQ Dead Letter queue name -->
<add key="deadLetterQueueName" value=".\private$\ServiceModelSamplesOrdersAppDLQ"/>
</appSettings>
<system.serviceModel>
<client>
<!-- Define NetMsmqEndpoint -->
<endpoint name="OrderProcessorEndpoint"
address="net.msmq://localhost/private/ServiceModelSamplesDeadLetter"
binding="netMsmqBinding"
bindingConfiguration="PerAppDLQBinding"
contract="IOrderProcessor" />
</client>
<bindings>
<netMsmqBinding>
<binding name="PerAppDLQBinding"
deadLetterQueue="Custom"
customDeadLetterQueue="net.msmq://localhost/private/ServiceModelSamplesOrdersAppDLQ"
timeToLive="00:00:02"/>
</netMsmqBinding>
</bindings>
</system.serviceModel>
</configuration>
Der Dienst für unzustellbare Nachrichten liest Nachrichten aus der Warteschlange für unzustellbare Nachrichten. Der Dienst für unzustellbare Nachrichten implementiert den IOrderProcessor-Vertrag. Die Implementierung besteht jedoch nicht darin, Bestellungen zu verarbeiten. Der Dienst für unzustellbare Nachrichten ist ein Clientdienst und besitzt keine Funktion für die Verarbeitung von Aufträgen.
Hinweis
Die Warteschlange für unzustellbare Nachrichten ist eine Clientwarteschlange und befindet sich lokal zum Clientwarteschlangen-Manager.
Die Implementierung des Dienst für unzustellbare Nachrichten überprüft die Ursache für die fehlgeschlagene Zustellung und ergreift Abhilfemaßnahmen. Der Grund für einen Nachrichtenfehler wird in zwei Enumerationen erfasst, DeliveryFailure und DeliveryStatus. Sie können MsmqMessageProperty aus OperationContext abrufen, wie im folgenden Beispielcode gezeigt.
public void SubmitPurchaseOrder(PurchaseOrder po)
{
Console.WriteLine("Submitting purchase order did not succeed ", po);
MsmqMessageProperty mqProp =
OperationContext.Current.IncomingMessageProperties[
MsmqMessageProperty.Name] as MsmqMessageProperty;
Console.WriteLine("Message Delivery Status: {0} ",
mqProp.DeliveryStatus);
Console.WriteLine("Message Delivery Failure: {0}",
mqProp.DeliveryFailure);
Console.WriteLine();
…
}
Nachrichten in der Dead-Letter-Queue sind Nachrichten, die an den Dienst adressiert sind, der sie verarbeitet. Wenn der Dienst für unzustellbare Nachrichten Nachrichten aus der Warteschlange liest, findet daher die WCF-Kanalebene (Windows Communication Foundation) die fehlende Übereinstimmung bei den Endpunkten, sodass die Nachricht nicht versendet wird. In diesem Fall ist die Nachricht an den Auftragsverarbeitungsdienst adressiert, wird jedoch vom Dienst für unzustellbare Nachrichten empfangen. Um eine Nachricht zu empfangen, die an einen anderen Endpunkt adressiert ist, wird ein Adressfilter angegeben, der mit jeder Adresse übereinstimmt.ServiceBehavior Dies ist erforderlich, um Nachrichten, die aus der Warteschlange für unzustellbare Nachrichten gelesen werden, erfolgreich zu verarbeiten.
In diesem Beispiel wird die Nachricht vom Dienst für unzustellbare Nachrichten erneut gesendet, wenn der Grund für den Fehler darin besteht, dass für die Nachricht ein Timeout aufgetreten ist. Bei allen anderen Ursachen wird der Übermittlungsfehler angezeigt, wie aus dem folgenden Beispielcode ersichtlich:
// Service class that implements the service contract.
// Added code to write output to the console window.
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single, ConcurrencyMode=ConcurrencyMode.Single, AddressFilterMode=AddressFilterMode.Any)]
public class PurchaseOrderDLQService : IOrderProcessor
{
OrderProcessorClient orderProcessorService;
public PurchaseOrderDLQService()
{
orderProcessorService = new OrderProcessorClient("OrderProcessorEndpoint");
}
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public void SubmitPurchaseOrder(PurchaseOrder po)
{
Console.WriteLine("Submitting purchase order did not succeed ", po);
MsmqMessageProperty mqProp = OperationContext.Current.IncomingMessageProperties[MsmqMessageProperty.Name] as MsmqMessageProperty;
Console.WriteLine("Message Delivery Status: {0} ", mqProp.DeliveryStatus);
Console.WriteLine("Message Delivery Failure: {0}", mqProp.DeliveryFailure);
Console.WriteLine();
// resend the message if timed out
if (mqProp.DeliveryFailure == DeliveryFailure.ReachQueueTimeout ||
mqProp.DeliveryFailure == DeliveryFailure.ReceiveTimeout)
{
// re-send
Console.WriteLine("Purchase order Time To Live expired");
Console.WriteLine("Trying to resend the message");
// reuse the same transaction used to read the message from dlq to enqueue the message to app. queue
orderProcessorService.SubmitPurchaseOrder(po);
Console.WriteLine("Purchase order resent");
}
}
// Host the service within this EXE console application.
public static void Main()
{
// Create a ServiceHost for the PurchaseOrderDLQService type.
using (ServiceHost serviceHost = new ServiceHost(typeof(PurchaseOrderDLQService)))
{
// Open the ServiceHostBase to create listeners and start listening for messages.
serviceHost.Open();
// The service can now be accessed.
Console.WriteLine("The dead letter service is ready.");
Console.WriteLine("Press <ENTER> to terminate service.");
Console.WriteLine();
Console.ReadLine();
}
}
}
Im folgenden Beispiel wird die Konfiguration für eine unzustellbare Nachricht veranschaulicht:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<services>
<service
name="Microsoft.ServiceModel.Samples.PurchaseOrderDLQService">
<!-- Define NetMsmqEndpoint in this case, DLQ end point to read messages-->
<endpoint address="net.msmq://localhost/private/ServiceModelSamplesOrdersAppDLQ"
binding="netMsmqBinding"
bindingConfiguration="DefaultBinding"
contract="Microsoft.ServiceModel.Samples.IOrderProcessor" />
</service>
</services>
<client>
<!-- Define NetMsmqEndpoint -->
<endpoint name="OrderProcessorEndpoint"
address="net.msmq://localhost/private/ServiceModelSamplesDeadLetter"
binding="netMsmqBinding"
bindingConfiguration="SystemDLQBinding"
contract="IOrderProcessor" />
</client>
<bindings>
<netMsmqBinding>
<binding name="DefaultBinding" />
<binding name="SystemDLQBinding"
deadLetterQueue="System"/>
</netMsmqBinding>
</bindings>
</system.serviceModel>
</configuration>
Beim Ausführen des Beispiels gibt es drei ausführbare Dateien, die ausgeführt werden müssen, um zu sehen, wie die Fehlermeldungswarteschlange für jede Anwendung funktioniert: Der Client, der Dienst und ein Dead-Letter-Dienst, der aus der Fehlermeldungswarteschlange für jede Anwendung liest und die Nachricht erneut an den Dienst sendet. Alle Konsolenanwendungen mit Ausgabe in Konsolenfenstern.
Hinweis
Da die Warteschlange verwendet wird, müssen der Client und der Dienst nicht gleichzeitig laufen. Sie können den Client ausführen, ihn herunterfahren und dann den Dienst starten und trotzdem seine Nachrichten erhalten. Sie sollten den Dienst starten und wieder schließen, damit die Warteschlange erstellt werden kann.
Beim Ausführen des Clients zeigt der Client die Meldung an:
Press <ENTER> to terminate client.
Der Client hat versucht, die Nachricht zu senden, aufgrund des kurzen Zeitlimits ist die Nachricht jedoch abgelaufen und befindet sich jetzt in der Warteschlange für unzustellbare Nachrichten für jede Anwendung.
Anschließend führen Sie den Dead-Letter-Dienst aus, der die Nachricht liest, den Fehlercode anzeigt und die Nachricht an den Dienst zurücksendet.
The dead letter service is ready.
Press <ENTER> to terminate service.
Submitting purchase order did not succeed
Message Delivery Status: InDoubt
Message Delivery Failure: ReachQueueTimeout
Purchase order Time To Live expired
Trying to resend the message
Purchase order resent
Der Dienst startet und liest dann die erneut gesendete Nachricht und verarbeitet sie.
The service is ready.
Press <ENTER> to terminate service.
Processing Purchase Order: 97897eff-f926-4057-a32b-af8fb11b9bf9
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.
Um das Beispiel in einer einzelnen oder computerübergreifenden Konfiguration auszuführen, ändern Sie die Warteschlangennamen entsprechend, indem Sie localhost durch den vollständigen Namen des Computers ersetzen, und folgen Sie den Anweisungen unter Ausführen der Windows Communication Foundation-Beispiele.
So führen Sie das Beispiel auf einem Computer aus, der zu einer Arbeitsgruppe gehört
Wenn Ihr Computer nicht Teil einer Domäne ist, deaktivieren Sie die Transportsicherheit, indem Sie den Authentifizierungsmodus und die Schutzstufe wie
Nonein der folgenden Beispielkonfiguration gezeigt festlegen:<bindings> <netMsmqBinding> <binding name="TransactedBinding"> <security mode="None"/> </binding> </netMsmqBinding> </bindings>Stellen Sie sicher, dass der Endpunkt der Bindung zugeordnet ist, indem Sie das Attribut des Endpunkts
bindingConfigurationfestlegen.Stellen Sie sicher, dass Sie die Konfiguration auf dem DeadLetterService,-Server und dem Client ändern, bevor Sie das Beispiel ausführen.
Hinweis
Die Einstellung von
security modezuNoneentspricht der Einstellung der Sicherheit vonMsmqAuthenticationMode,MsmqProtectionLevelundMessagezuNone.
Kommentare
Standardmäßig wird mit der netMsmqBinding-Bindung die Transportsicherheit aktiviert. Zwei Eigenschaften MsmqAuthenticationMode und MsmqProtectionLevel, zusammen bestimmen den Typ der Transportsicherheit. Standardmäßig ist der Authentifizierungsmodus auf Windows und die Schutzebene auf .Sign Damit MSMQ die Authentifizierungs- und Signaturfunktion bereitstellt, muss sie Teil einer Domäne sein. Wenn Sie dieses Beispiel auf einem Computer ausführen, der nicht Teil einer Domäne ist, wird die folgende Fehlermeldung angezeigt: "Das interne Nachrichtenwarteschlangenzertifikat des Benutzers ist nicht vorhanden".