Verteilen nach TextelementDispatch by Body Element

Dieses Beispiel veranschaulicht, wie ein alternativer Algorithmus zum Zuweisen eingehender Nachrichten zu Vorgängen implementiert wird.This sample demonstrates how to implement an alternate algorithm for assigning incoming messages to operations.

Standardmäßig wählt der Dienstmodellverteiler die passende Verarbeitungsmethode für eine eingehende Nachricht auf der Grundlage des WS-Adressierungsaktionsheaders der Nachricht aus bzw. auf der Grundlage der entsprechenden Informationen in der HTTP SOAP-Anforderung.By default, the service model dispatcher selects the appropriate handling method for an incoming message based on the message's WS-Addressing "Action" header or the equivalent information in the HTTP SOAP request.

Einige SOAP 1.1-Webdienststapel, die nicht den WS-I Basic Profile 1.1-Richtlinien folgen, verteilen Nachrichten nicht auf der Grundlage des Aktions-URIs, sondern auf der Grundlage des qualifizierten XML-Namens des ersten Elements innerhalb des SOAP-Nachrichtentexts.Some SOAP 1.1 Web services stacks that do not follow the WS-I Basic Profile 1.1 guidelines do not dispatch messages based on the Action URI, but rather based on the XML qualified name of the first element inside the SOAP body. Gleichzeitig kann die Clientseite dieser Stapel Nachrichten mit einem leeren oder beliebigen HTTP SoapAction-Header senden, da dies mit den SOAP 1.1-Spezifikationen zulässig ist.Likewise, the client side of these stacks might send messages with an empty or arbitrary HTTP SoapAction header, which was permitted by the SOAP 1.1 specification.

Um das Verfahren zu ändern, mit dem Nachrichten an Methoden verteilt werden, implementiert das Beispiel die IDispatchOperationSelector-Erweiterbarkeitsschnittstelle auf dem DispatchByBodyElementOperationSelector.To change the way messages are dispatched to methods, the sample implements the IDispatchOperationSelector extensibility interface on the DispatchByBodyElementOperationSelector. Diese Klasse wählt Operationen auf der Grundlage des ersten Elements des Nachrichtentexts aus.This class selects operations based on the first element of the message body.

Der Konstruktor erwartet ein mit Paaren von XmlQualifiedName und Zeichenketten gefülltes Wörterbuch, dabei geben die qualifizierten Namen den Namen des ersten untergeordneten Elements des SOAP-Nachrichtentexts an, und die Zeichenketten geben den entsprechenden Vorgangsnamen an.The class constructor expects a dictionary populated with pairs of XmlQualifiedName and strings, whereby the qualified names indicate the name of the first child of the SOAP body and the strings indicate the matching operation name. Der defaultOperationName ist der Name des Vorgangs, der alle Nachrichten empfängt, die nicht mit diesem Wörterbuch abgeglichen werden können.The defaultOperationName is the name of the operation that receives all messages that cannot be matched against this dictionary:

class DispatchByBodyElementOperationSelector : IDispatchOperationSelector  
{  
    Dictionary<XmlQualifiedName, string> dispatchDictionary;  
    string defaultOperationName;  

    public DispatchByBodyElementOperationSelector(Dictionary<XmlQualifiedName,string> dispatchDictionary, string defaultOperationName)  
    {  
        this.dispatchDictionary = dispatchDictionary;  
        this.defaultOperationName = defaultOperationName;  
    }  

IDispatchOperationSelector-Implementierungen sind sehr einfach zu erstellen, da die Schnittstelle nur eine Methode besitzt: SelectOperation.IDispatchOperationSelector implementations are very straightforward to build as there is only one method on the interface: SelectOperation. Die Aufgabe dieser Methode ist, eingehende Nachrichten zu überprüfen und eine Zeichenkette zurückzugeben, die dem Namen einer Methode auf dem Dienstvertrag für den aktuellen Endpunkt entspricht.The job of this method is to inspect an incoming message and to return a string that equals the name of a method on the service contract for the current endpoint.

In diesem Beispiel ruft die Vorgangsauswahl mithilfe von XmlDictionaryReader einen GetReaderAtBodyContents für den Text der eingehenden Nachricht ab.In this sample, the operation selector acquires an XmlDictionaryReader for the incoming message's body using GetReaderAtBodyContents. Diese Methode setzt den Leser bereits auf das erste untergeordnete Element des Nachrichtentexts, sodass es ausreicht, den aktuellen Namen des Elements und den Namespace-URI abzurufen und diese zu einem XmlQualifiedName zu kombinieren, der dann für die Suche nach dem entsprechenden Vorgang aus dem Wörterbuch der Vorgangsauswahl verwendet wird.This method already positions the reader on the first child of the message's body so that it is sufficient to get the current element's name and namespace URI and combine them into an XmlQualifiedName that is then used for looking up the corresponding operation from the dictionary held by the operation selector.

public string SelectOperation(ref System.ServiceModel.Channels.Message message)  
{  
    XmlDictionaryReader bodyReader = message.GetReaderAtBodyContents();  
    XmlQualifiedName lookupQName = new  
       XmlQualifiedName(bodyReader.LocalName, bodyReader.NamespaceURI);  
    message = CreateMessageCopy(message,bodyReader);  
    if (dispatchDictionary.ContainsKey(lookupQName))  
    {  
         return dispatchDictionary[lookupQName];  
    }  
    else  
    {  
        return defaultOperationName;  
    }  
}  

Wenn mit GetReaderAtBodyContents oder einer der anderen Methoden, die Zugriff auf den Nachrichtentext haben, auf den Nachrichtentext zugegriffen wird, wird die Nachricht als "gelesen" markiert, was bedeutet, dass die Nachricht für weitere Verarbeitung nicht mehr zur Verfügung steht.Accessing the message body with GetReaderAtBodyContents or any of the other methods that provide access to the message's body content causes the message to be marked as "read", which means that the message is invalid for any further processing. Daher erstellt die Vorgangsauswahl mithilfe der im folgenden Code dargestellten Methode eine Kopie der eingehenden Nachricht.Therefore, the operation selector creates a copy of the incoming message with the method shown in the following code. Da die Position des Lesers während der Überprüfung nicht geändert wurde, kann auf diesen durch die neu erstellte Nachricht verwiesen werden, in die auch die Nachrichteneigenschaften und die Nachrichtenheader kopiert werden, sodass eine exakte Kopie der ursprünglichen Nachricht entsteht.Because the reader's position has not been changed during the inspection, it can be referenced by the newly created message to which the message properties and the message headers are also copied, which results in an exact clone of the original message:

private Message CreateMessageCopy(Message message,   
                                     XmlDictionaryReader body)  
{  
    Message copy = Message.CreateMessage(message.Version,message.Headers.Action,body);  
    copy.Headers.CopyHeaderFrom(message,0);  
    copy.Properties.CopyProperties(message.Properties);  
    return copy;  
}  

Hinzufügen einer Vorgangsauswahl zu einem DienstAdding an Operation Selector to a Service

Dienstverteilungs-vorgangsauswahlen sind Erweiterungen der Windows Communication Foundation (WCF)-Verteiler.Service dispatch operation selectors are extensions to the Windows Communication Foundation (WCF) dispatcher. Für die Auswahl von Methoden auf dem Rückrufkanal von Duplexverträgen stehen auch Clientvorgangsauswahlen zur Verfügung, die ähnlich funktionieren wie die hier erläuterten Verteilungsvorgangsauswahlen, die jedoch nicht explizit in diesem Beispiel behandelt werden.For selecting methods on the callback channel of duplex contracts, there are also client operation selectors, which work very much like the dispatch operation selectors described here, but which are not explicitly covered in this sample.

Wie die meisten Dienstmodellerweiterungen werden auch Verteilungsvorgangsauwahlen dem Verteiler mithilfe von Verhaltensweisen hinzugefügt.Like most service model extensions, dispatch operation selectors are added to the dispatcher using behaviors. Ein Verhalten ist ein Konfigurationsobjekt, das eine oder mehrere Erweiterungen hinzufügt, an der verteilungslaufzeit (oder der Clientlaufzeit) oder andere Weise ändert die Einstellungen.A behavior is a configuration object, which either adds one or more extensions to the dispatch runtime (or to the client runtime) or otherwise changes its settings.

Da Vorgangsauswahlen Vertragsbereiche besitzen, ist das entsprechende Verhalten, das hier implementiert wird, IContractBehavior.Because operation selectors have contract scope, the appropriate behavior to implement here is the IContractBehavior. Da die Schnittstelle auf einer von Attribute abgeleiteten Klasse implementiert wird, wie im folgenden Code dargestellt, kann das Verhalten deklarativ zu jedem Dienstvertrag hinzugefügt werden.Because the interface is implemented on a Attribute derived class as shown in the following code, the behavior can be declaratively added to any service contract. Immer wenn ein ServiceHost geöffnet und die Verteilungslaufzeit erstellt wird, werden alle Verhalten, die als Attribute auf Verträgen, Vorgängen und Dienstimplementierungen oder als Element in der Dienstkonfiguration gefunden werden, automatisch hinzugefügt und der Reihe nach auf Erweiterungen oder Änderungen der Standardkonfiguration abgefragt.Whenever a ServiceHost is opened and the dispatch runtime is built, all behaviors found either as attributes on contracts, operations, and service implementations or as element in the service configuration are automatically added and subsequently asked to contribute extensions or modify the default configuration.

Der Kürze wegen zeigt der folgende Codeauszug nur die Implementierung der Methode ApplyDispatchBehavior, die die Konfigurationsänderung für den Verteiler in diesem Beispiel bewirkt.For brevity, the following code excerpt only shows the implementation of the method ApplyDispatchBehavior, which effects the configuration changes for the dispatcher in this sample. Die anderen Methoden werden nicht dargestellt, da sie zum Aufrufer zurückkehren, ohne eine Aufgabe auszuführen.The other methods are not shown because they return to the caller without doing any work.

[AttributeUsage(AttributeTargets.Class|AttributeTargets.Interface)]  
class DispatchByBodyElementBehaviorAttribute : Attribute, IContractBehavior  
{  
    // public void AddBindingParameters(...)   
    // public void ApplyClientBehavior(...)  
    // public void Validate(...)  

Zuerst richtet die ApplyDispatchBehavior-Implementierung das Suchwörterbuch für die Vorgangsauswahl ein, indem die OperationDescription-Elemente in der ContractDescription der Dienstendpunkte durchlaufen werden.First, the ApplyDispatchBehavior implementation sets up the lookup dictionary for the operation selector by iterating over the OperationDescription elements in the service endpoint's ContractDescription. Anschließend wird jede Vorgangsauswahl auf das Vorhandensein des DispatchBodyElementAttribute-Verhaltens untersucht, einer Implementierung vonIOperationBehavior, das ebenfalls im Beispiel definiert ist.Then, each operation description is inspected for the presence of the DispatchBodyElementAttribute behavior, an implementation of IOperationBehavior that is also defined in this sample. Diese Klasse ist zwar ebenfalls ein Verhalten, sie ist jedoch passiv und bewirkt keine aktiven Konfigurationsänderungen an der Verteilungslaufzeit.While this class is also a behavior, it is passive and does not actively contribute any configuration changes to the dispatch runtime. All ihre Methoden kehren zum Aufrufer zurück, ohne eine Aktion auszuführen.All of its methods return to the caller without taking any actions. Das Vorgangsverhalten ist nur vorhanden, damit die für den neuen Verteilungsmechanismus erforderlichen Metadaten d.h. der qualifizierte Name des Textelements, bei dessen Auftreten ein Vorgang ausgewählt wird den entsprechenden Vorgängen zugeordnet werden können.The operation behavior only exists so that the metadata required for the new dispatch mechanism, namely the qualified name of the body element on whose occurrence an operation is selected, can be associated with the respective operations.

Wenn ein solches Verhalten gefunden wird, werden dem Wörterbuch ein aus dem qualifizierten XML-Namen gebildetes Wertepaar (QName-Eigenschaft) und der Vorgangsname (Name-Eigenschaft) hinzugefügt.If such a behavior is found, a value pair created from the XML qualified name (QName property) and the operation name (Name property) is added to the dictionary.

Nachdem das Wörterbuch gefüllt wurde, wird eine neue DispatchByBodyElementOperationSelector mit diesen Informationen erstellt und als Vorgangsauswahl der Verteilungslaufzeit festgelegt:Once the dictionary is populated, a new DispatchByBodyElementOperationSelector is constructed with this information and set as the operation selector of the dispatch runtime:

public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.DispatchRuntime dispatchRuntime)  
{  
    Dictionary<XmlQualifiedName,string> dispatchDictionary =   
                     new Dictionary<XmlQualifiedName,string>();  
    foreach( OperationDescription operationDescription in   
                              contractDescription.Operations )  
    {  
        DispatchBodyElementAttribute dispatchBodyElement =   
   operationDescription.Behaviors.Find<DispatchBodyElementAttribute>();  
        if ( dispatchBodyElement != null )  
        {  
             dispatchDictionary.Add(dispatchBodyElement.QName,   
                              operationDescription.Name);  
        }  
    }  
    dispatchRuntime.OperationSelector =   
            new DispatchByBodyElementOperationSelector(  
               dispatchDictionary,   
               dispatchRuntime.UnhandledDispatchOperation.Name);  
    }  
}  

Implementieren des DienstsImplementing the Service

Das in diesem Beispiel implementierte Verhalten wirkt sich unmittelbar darauf aus, wie übermittelte Nachrichten interpretiert und verteilt werden. Dies ist eine Funktion des Dienstvertrags.The behavior implemented in this sample directly affects how messages from the wire are interpreted and dispatched, which is a function of the service contract. Daher sollte das Verhalten auf Dienstvertragsebene in jeder Dienstimplementierung deklariert werden, die das Verhalten verwendet.Consequently, the behavior should be declared on the service contract level in any service implementation that chooses to use it.

Der beispielprojektdienst wendet die DispatchByBodyElementBehaviorAttribute -Vertragsverhalten auf den IDispatchedByBody -Dienstvertrag an und bezeichnet jede der beiden Vorgänge OperationForBodyA() und OperationForBodyB() mit einem DispatchBodyElementAttribute Vorgangsverhalten.The sample project service applies the DispatchByBodyElementBehaviorAttribute contract behavior to the IDispatchedByBody service contract and labels each of the two operations OperationForBodyA() and OperationForBodyB() with a DispatchBodyElementAttribute operation behavior. Wenn ein Diensthost für einen Dienst, der diesen Vertrag implementiert, geöffnet wird, werden diese Metadaten von dem Verteilungsersteller wie zuvor erläutert ausgewählt.When a service host for a service that implements this contract is opened, this metadata is picked up by the dispatcher builder as previously described.

Da die Vorgangsauswahl die Verteilung nur auf der Grundlage des Nachrichtentexts ausführt und die "Aktion" ignoriert, muss der Laufzeit mitgeteilt werden, nicht die Aktionsheader in den zurückgegebenen Antworten zu überprüfen. Weisen Sie dazu der ReplyAction-Eigenschaft von OperationContractAttribute den Platzhalter "*" zu.Because the operation selector dispatches solely based on the message body element and ignores the "Action", it is required to tell the runtime not to check the "Action" header on the returned replies by assigning the wildcard "*" to the ReplyAction property of OperationContractAttribute. Darüber hinaus ist es erforderlich, um ein Standardvorgang vorhanden sein, die die "Aktion"-Eigenschaft auf den Platzhalter "*".Furthermore, it is required to have a default operation that has the "Action" property set to the wildcard "*". Der Standardvorgang empfängt alle Nachrichten, die nicht verteilt werden können und kein DispatchBodyElementAttribute besitzen:The default operation receives all messages which cannot be dispatched and does not have a DispatchBodyElementAttribute:

[ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples"),  
                            DispatchByBodyElementBehavior]  
public interface IDispatchedByBody  
{  
    [OperationContract(ReplyAction="*"),   
     DispatchBodyElement("bodyA","http://tempuri.org")]  
    Message OperationForBodyA(Message msg);  
    [OperationContract(ReplyAction = "*"),   
     DispatchBodyElement("bodyB", "http://tempuri.org")]  
    Message OperationForBodyB(Message msg);  
    [OperationContract(Action="*", ReplyAction="*")]  
    Message DefaultOperation(Message msg);  
}  

Die Beispieldienstimplementierung ist einfach.The sample service implementation is straightforward. Jede Methode schließt die empfangene Nachricht in eine Antwortnachricht ein und sendet sie zurück an den Client.Every method wraps the received message into a reply message and echoes it back to the client.

Erstellen und Ausführen des BeispielsRunning and Building the Sample

Wenn Sie das Beispiel ausführen, wird der Textinhalt der Vorgangsantworten im Clientkonsolenfenster angezeigt, ähnlich der folgenden (formatierten) Ausgabe.When you run the sample, the body content of the operation responses are displayed in the client console window similar to the following (formatted) output.

Der Client sendet drei Nachrichten an den Dienst, dessen Textinhaltselemente entsprechend mit bodyA, bodyB und bodyX benannt werden.The client sends three messages to the service whose body content element is named bodyA, bodyB, and bodyX, respectively. Wie aus der vorstehenden Beschreibung und dem dargestellten Dienstvertrag hervorgeht, wird die eingehende Nachricht mit dem bodyA-Element an die OperationForBodyA()-Methode weitergeleitet.As can be deferred from the previous description and the service contract shown, the incoming message with the bodyA element is dispatched to the OperationForBodyA() method. Da kein explizites Verteilungsziel für die Nachricht mit dem Textelement bodyX vorhanden ist, wird die Nachricht an den DefaultOperation() weitergeleitet.Because there is no explicit dispatch target for the message with the bodyX body element, the message is dispatched to the DefaultOperation(). Jeder der Dienstvorgänge schließt den empfangenen Nachrichtentext in ein Element ein, das spezifisch für die Methode ist, und sendet ihn zurück. Dies dient dazu, dass sich Eingangs- und Ausgangsnachricht in diesem Beispiel eindeutig entsprechen.Each of the service operations wraps the received message body into an element specific to the method and returns it, which is done to correlate input and output messages clearly for this sample:

<?xml version="1.0" encoding="IBM437"?>  
<replyBodyA xmlns="http://tempuri.org">  
   <q:bodyA xmlns:q="http://tempuri.org">test</q:bodyA>  
</replyBodyA>  
<?xml version="1.0" encoding="IBM437"?>  
<replyBodyB xmlns="http://tempuri.org">  
  <q:bodyB xmlns:q="http://tempuri.org">test</q:bodyB>  
</replyBodyB>  
<?xml version="1.0" encoding="IBM437"?>  
<replyDefault xmlns="http://tempuri.org">  
   <q:bodyX xmlns:q="http://tempuri.org">test</q:bodyX>  
</replyDefault>  

So können Sie das Beispiel einrichten, erstellen und ausführenTo set up, 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. Führen Sie zum Erstellen der Projektmappe die Anweisungen im Erstellen der Windows Communication Foundation-Beispiele.To build the solution, follow the instructions in Building the Windows Communication Foundation Samples.

  3. Um das Beispiel in einer einzelnen oder computerübergreifenden Konfiguration ausführen möchten, folgen Sie den Anweisungen Ausführen der Windows Communication Foundation-Beispiele.To run the sample in a single- or cross-machine configuration, follow the instructions in Running the Windows Communication Foundation Samples.

Wichtig

Die Beispiele sind möglicherweise bereits auf dem Computer installiert.The samples may already be installed on your machine. 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, fahren Sie mit Windows Communication Foundation (WCF) und Windows Workflow Foundation (WF) Samples for .NET Framework 4 aller Windows Communication Foundation (WCF) herunterladen und WFWF Beispiele.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) and WFWF samples. Dieses Beispiel befindet sich im folgenden Verzeichnis.This sample is located in the following directory.

<InstallDrive>:\WF_WCF_Samples\WCF\Extensibility\Interop\AdvancedDispatchByBody

Siehe auchSee Also