Benutzerdefinierter Demux
In diesem Beispiel wird veranschaulicht, wie MSMQ-Nachrichtenheader unterschiedlichen Dienstvorgängen zugeordnet werden können, damit Windows Communication Foundation (WCF)-Dienste, die MsmqIntegrationBinding verwenden, nicht auf die Verwendung eines einzigen Dienstvorgangs beschränkt sind, wie in den Beispielen Message Queuing zu Windows Communication Foundation und Windows Communication Foundation zu Message Queuing dargestellt.
Der Dienst ist in diesem Beispiel eine selbst gehostete Konsolenanwendung, sodass Sie den Dienst beobachten können, der Nachrichten in Warteschlangen empfängt.
Der Dienstvertrag ist IOrderProcessor
und definiert einen unidirektionalen Dienst, der für die Verwendung mit Warteschlangen geeignet ist.
[ServiceContract]
[KnownType(typeof(PurchaseOrder))]
[KnownType(typeof(String))]
public interface IOrderProcessor
{
[OperationContract(IsOneWay = true, Name = "SubmitPurchaseOrder")]
void SubmitPurchaseOrder(MsmqMessage<PurchaseOrder> msg);
[OperationContract(IsOneWay = true, Name = "CancelPurchaseOrder")]
void CancelPurchaseOrder(MsmqMessage<string> ponumber);
}
Eine MSMQ-Nachricht besitzt keinen Aktionsheader. Es ist nicht möglich, Vorgangsverträgen unterschiedliche MSMQ-Nachrichten automatisch zuzuordnen. Deshalb kann es nur einen Vorgangsvertrag geben. Um diese Einschränkung zu umgehen, implementiert der Dienst die SelectOperation-Methode der IDispatchOperationSelector-Schnittstelle. Die SelectOperation-Methode ermöglicht dem Dienst, einem bestimmten Dienstvorgang einen bestimmten Nachrichtenheader zuzuordnen. In diesem Beispiel wird den Dienstvorgängen der Bezeichnungsheader der Nachricht zugeordnet. Der Name
-Parameter des Vorgangsvertrags legt fest, welcher Dienstvorgang für eine bestimmte Nachrichtenbezeichnung weitergeleitet werden muss. Wenn der Bezeichnungsheader der Nachricht z. B. "SubmitPurchaseOrder" enthält, wird der "SubmitPurchaseOrder"-Dienstvorgang aufgerufen.
public class OperationSelector : IDispatchOperationSelector
{
public string SelectOperation(ref System.ServiceModel.Channels.Message message)
{
MsmqIntegrationMessageProperty property = MsmqIntegrationMessageProperty.Get(message);
return property.Label;
}
}
Der Dienst muss die ApplyDispatchBehavior-Methode der IContractBehavior-Schnittstelle implementieren, wie im folgenden Beispielcode dargestellt. Diese wendet den benutzerdefinierten OperationSelector
auf die Dienstframework-Dispatchlaufzeit an.
void IContractBehavior.ApplyDispatchBehavior(ContractDescription description, ServiceEndpoint endpoint, DispatchRuntime dispatch)
{
dispatch.OperationSelector = new OperationSelector();
}
Eine Nachricht muss den ContractFilter des Verteilers durchlaufen, bevor die Vorgangsauswahl erreicht wird. Standardmäßig wird eine Nachricht zurückgewiesen, wenn ihre Aktion auf keinem der vom Dienst implementierten Verträge gefunden werden kann. Um diese Prüfung zu vermeiden, implementieren wir ein IEndpointBehavior namens MatchAllFilterBehavior
, das es allen Nachrichten ermöglicht, den ContractFilter
zu passieren, indem der MatchAllMessageFilter folgendermaßen angewendet wird.
public void ApplyDispatchBehavior(ServiceEndpoint serviceEndpoint, EndpointDispatcher endpointDispatcher)
{
endpointDispatcher.ContractFilter = new MatchAllMessageFilter();
}
Wenn der Dienst eine Nachricht empfängt, wird der entsprechende Dienstvorgang mithilfe der Informationen im Bezeichnungsheader verteilt. Der Nachrichtentext wird in ein PurchaseOrder
-Objekt deserialisiert, wie im folgenden Beispielcode dargestellt.
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public void SubmitPurchaseOrder(MsmqMessage<PurchaseOrder> msg)
{
PurchaseOrder po = (PurchaseOrder)msg.Body;
Random statusIndexer = new Random();
po.Status = (OrderStates)statusIndexer.Next(3);
Console.WriteLine("Processing {0} ", po);
}
Der Dienst ist selbst gehostet. Bei der Verwendung von MSMQ muss die Warteschlange im Voraus erstellt werden. Dies kann manuell erfolgen oder mithilfe eines Codes. In diesem Beispiel enthält der Dienst einen Code, um zu überprüfen, ob die Warteschlange bereits vorhanden ist und um die Warteschlange gegebenenfalls zu erstellen. Der Warteschlangenname wird aus der Konfigurationsdatei gelesen.
public static void Main()
{
// Get MSMQ queue name from app 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 CalculatorService type.
using (ServiceHost serviceHost = new ServiceHost(typeof(OrderProcessorService)))
{
ServiceEndpoint endpoint = serviceHost.Description.Endpoints[0];
endpoint.Behaviors.Add(new MatchAllFilterBehavior());
//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.ReadLine();
// Close the ServiceHost to shutdown the service.
serviceHost.Close();
}
}
Der MSMQ-Warteschlangenname wird im appSettings-Abschnitt der Konfigurationsdatei angegeben.
Tipp
Im Warteschlangennamen wird ein Punkt (.) für den lokalen Computer und in der Pfadangabe werden umgekehrte Schrägstriche als Trennzeichen verwendet. Die WCF-Endpunktadresse legt ein "msmq.formatname"-Schema fest und verwendet "localhost" für den lokalen Computer. Dem Schema folgt eine ordnungemäß entsprechend den Namens- und Adressierungsrichtlinien des MSMQ-Formats formatierte Warteschlangenadresse.
<appSettings>
<!-- Use appSetting to configure the MSMQ queue name. -->
<add key="queueName" value=".\private$\Orders" />
</appSettings>
Tipp
Dieses Beispiel erfordert die Installation von Message Queuing(möglicherweise nur in englischer Sprache).
Starten Sie den Dienst, und führen Sie den Client aus.
Auf dem Client wird die folgende Ausgabe angezeigt.
Placed the order:Purchase Order: 28fc457a-1a56-4fe0-9dde-156965c21ed6
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
Cancelled the Order: 28fc457a-1a56-4fe0-9dde-156965c21ed6
Press <ENTER> to terminate client.
Auf dem Dienst muss die folgende Ausgabe angezeigt werden.
The service is ready.
Press <ENTER> to terminate service.
Processing Purchase Order: 28fc457a-1a56-4fe0-9dde-156965c21ed6
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: Shipped
Purchase Order 28fc457a-1a56-4fe0-9dde-156965c21ed6 is cancelled
So richten Sie das Beispiel ein, erstellen es und führen es aus
Vergewissern Sie sich, dass Sie Beispiele zum einmaligen Setupverfahren für Windows Communication Foundation ausgeführt haben.
Zum Erstellen der C#- oder Visual Basic .NET-Edition der Projektmappe befolgen Sie die unter Erstellen der Windows Communication Foundation-Beispiele aufgeführten Anweisungen.
Wenn Sie das Beispiel in einer Konfiguration mit einem Computer oder computerübergreifend ausführen möchten, folgen Sie den unter Durchführen der Windows Communication Foundation-Beispiele aufgeführten Anweisungen.
So führen Sie das Beispiel computerübergreifend aus
Kopieren Sie die Dienstprogrammdateien aus dem Ordner "\service\bin\" (unterhalb des sprachspezifischen Ordners) auf den Dienstcomputer.
Kopieren Sie die Clientprogrammdateien aus dem Ordner "\client\bin\" (unterhalb des sprachspezifischen Ordners) auf den Clientcomputer.
Ändern Sie in der Datei "Client.exe.config" den "orderQueueName", um den Dienstcomputer anstelle von "." anzugeben.
Starten Sie auf dem Dienstcomputer die Datei "Service.exe" über eine Eingabeaufforderung.
Starten Sie auf dem Clientcomputer in einer Eingabeaufforderung die Datei "Client.exe".
Siehe auch
Weitere Ressourcen
Queuing in WCF
Message Queuing
Send comments about this topic to Microsoft.
© 2007 Microsoft Corporation. All rights reserved.