Freigeben über


Verwenden der Meldungsklasse

Die Message-Klasse ist für Windows Communication Foundation (WCF) wesentlich. Die gesamte Kommunikation zwischen Clients und Diensten führt letztlich zu gesendeten und empfangenen Message-Instanzen.

Sie würden normalerweise nicht direkt mit der Message-Klasse interagieren. Stattdessen werden WCF-Dienstmodellkonstrukte wie Datenverträge, Nachrichtenverträge und Vorgangsverträge zum Beschreiben von ein- und ausgehenden Nachrichten verwendet. In einigen komplexen Szenarien können Sie jedoch direkt mit der Message-Klasse programmieren. Die Verwendung der Message-Klasse kann beispielsweise in den folgenden Fällen erforderlich sein:

  • Wenn Sie eine alternative Methode zum Erstellen des Inhalts ausgehender Nachrichten (z. B. Erstellen einer Nachricht direkt aus einer Datei auf der Festplatte) statt des Serialisierens von .NET Framework-Objekten benötigen.

  • Wenn Sie eine alternative Methode zum Verwenden des Inhalts eingehender Nachrichten (z. B. zum Anwenden einer XSLT-Transformation auf den unformatierten XML-Inhalt) statt des Deserialisierens in .NET Framework-Objekte benötigen.

  • Wenn Sie Nachrichten allgemein und unabhängig vom Nachrichteninhalt bearbeiten müssen (z. B. zum Routen oder Weiterleiten von Nachrichten beim Erstellen eines Routers, Lastenausgleichsmoduls oder Veröffentlichen-Abonnieren-Systems).

Machen Sie sich vor dem Verwenden der Message-Klasse mit der WCF Datenübertragungsarchitektur in Datenübertragungsarchitektur - Übersicht vertraut.

Eine Message ist ein Allzweckcontainer für Daten, ihr Design folgt aber eng dem Design einer Nachricht im SOAP-Protokoll. Wie in SOAP verfügt eine Nachricht über einen Nachrichtentext und einen Header. Der Nachrichtentext enthält die tatsächlichen Nutzlastdaten, während die Header zusätzliche benannte Datencontainer enthalten. Die Regeln für das Lesen und Schreiben von Text und Headern sind unterschiedlich, so werden die Header immer im Arbeitsspeicher gepuffert, und der Zugriff ist beliebig oft in beliebiger Reihenfolge möglich, während der Text nur einmal gelesen und in einem Stream übertragen werden kann. Normalerweise werden in SOAP der Nachrichtentext dem SOAP-Text und die Nachrichtenheader den SOAP-Headern zugeordnet.

Verwenden der Meldungsklasse in Vorgängen

Sie können die Message-Klasse als Eingabeparameter eines Vorgangs, als den Rückgabewert eines Vorgangs oder beides verwenden. Wenn Message an einer Stelle in einem Vorgang verwendet wird, gelten die folgenden Einschränkungen:

  • Der Vorgang kann über keinen out-Parameter oder ref-Parameter verfügen.

  • Es kann nicht mehr als einen input-Parameter geben. Wenn der Parameter vorhanden ist, muss er entweder eine Nachricht oder ein Nachrichtenvertragstyp sein.

  • Der Rückgabetyp muss entweder void, Message oder ein Nachrichtenvertragstyp sein.

Das folgende Codebeispiel enthält einen gültigen Vorgangsvertrag.

<ServiceContract()>  _
Public Interface IMyService
    <OperationContract()>  _
    Function GetData() As Message 
    
    <OperationContract()>  _
    Sub PutData(ByVal m As Message) 
End Interface
[ServiceContract]
public interface IMyService
{
    [OperationContract]
    Message GetData();

    [OperationContract]
    void PutData(Message m);
}

Erstellen grundlegender Nachrichten

Die Message-Klasse stellt statische CreateMessage-Factorymethoden bereit, mit denen Sie grundlegende Nachrichten erstellen können.

Alle CreateMessage-Überladungen nehmen einen Versionsparameter vom Typ MessageVersion an, der die für die Nachricht zu verwendende SOAP-Version und Version der WS-Adressierung angibt. Wenn Sie die gleichen Protokollversionen wie die eingehende Nachricht verwenden möchten, können Sie die IncomingMessageVersion-Eigenschaft auf der OperationContext-Instanz nutzen, die aus der Current-Eigenschaft abgerufen wurde. Die meisten CreateMessage-Überladungen haben außerdem einen Zeichenfolgenparameter, der die für die Nachricht zu verwendende SOAP-Aktion angibt. Die Version kann auf None festgelegt werden, um die Generierung des SOAP-Umschlags zu deaktivieren; die Nachricht besteht nur aus dem Text.

Erstellen von Nachrichten aus Objekten

Die grundlegendste CreateMessage-Überladung, die nur eine Version und eine Aktion annimmt, erstellt eine Nachricht, die keinen Text enthält. Eine weitere Überladung nimmt einen zusätzlichen Object-Parameter an; es wird eine Nachricht erstellt, deren Text die serialisierte Darstellung des entsprechenden Objekts ist. Verwenden Sie das DataContractSerializer mit Standardeinstellungen für die Serialisierung. Wenn Sie ein anderes Serialisierungsprogramm verwenden möchten oder das DataContractSerializer anders konfiguriert werden soll, verwenden Sie die CreateMessage-Überladung, die auch einen XmlObjectSerializer-Parameter annimmt.

Sie können z. B. zum Zurückgeben eines Objekts in einer Nachricht den folgenden Code verwenden.

Public Class MyService1
    Implements IMyService
    
    Public Function GetData() As Message _
     Implements IMyService.GetData
        Dim p As New Person()
        p.name = "John Doe"
        p.age = 42
        Dim ver As MessageVersion = _
          OperationContext.Current.IncomingMessageVersion
        Return Message.CreateMessage(ver, "GetDataResponse", p)

    End Function
    
    
    Public Sub PutData(ByVal m As Message) _
    Implements IMyService.PutData
        ' Not implemented.
    End Sub
End Class
<DataContract()>  _
Public Class Person
    <DataMember()>  _
    Public name As String
    <DataMember()>  _
    Public age As Integer
End Class
public class MyService1 : IMyService
{
    public Message GetData()
    {
        Person p = new Person();
        p.name = "John Doe";
        p.age = 42;
        MessageVersion ver = OperationContext.Current.IncomingMessageVersion;
        return Message.CreateMessage(ver, "GetDataResponse", p);
    }

    public void PutData(Message m)
    {
        // Not implemented.
    }
}
[DataContract]
public class Person
{
    [DataMember] public string name;
    [DataMember] public int age;
}

Erstellen von Nachrichten aus XML-Lesern

Bestimmte CreateMessage-Überladungen nehmen einen XmlReader oder einen XmlDictionaryReader für den Text anstelle eines Objekts an. In diesem Fall enthält der Text der Nachricht die XML, die aus dem Lesen des übergebenen XML-Readers resultiert. Der folgende Code gibt beispielsweise eine Nachricht mit aus einer XML-Datei gelesenem Textinhalt zurück:

Public Class MyService2
    Implements IMyService
    
    Public Function GetData() As Message Implements IMyService.GetData
        Dim stream As New FileStream("myfile.xml", FileMode.Open)
        Dim xdr As XmlDictionaryReader = _
        XmlDictionaryReader.CreateTextReader(stream, New XmlDictionaryReaderQuotas())
        Dim ver As MessageVersion = OperationContext.Current.IncomingMessageVersion
        Return Message.CreateMessage(ver, "GetDataResponse", xdr)

    End Function
    
    
    Public Sub PutData(ByVal m As Message) Implements IMyService.PutData

    End Sub
End Class
public class MyService2 : IMyService
{
    public Message GetData()
    {
        FileStream stream = new FileStream("myfile.xml",FileMode.Open);
        XmlDictionaryReader xdr =
               XmlDictionaryReader.CreateTextReader(stream, 
                           new XmlDictionaryReaderQuotas());
        MessageVersion ver = 
            OperationContext.Current.IncomingMessageVersion;
        return Message.CreateMessage(ver,"GetDataResponse",xdr);
    }

    public void PutData(Message m)
    {
        // Not implemented.
    }

}

Darüber hinaus gibt es CreateMessage-Überladungen, die einen XmlReader oder einen XmlDictionaryReader annehmen, der die gesamte Nachricht und nicht nur den Text darstellt. Diese Überladungen nehmen auch einen ganzzahligen maxSizeOfHeaders-Parameter an. Header werden immer in den Arbeitsspeicher gepuffert, sobald die Nachricht erstellt wurde, und dieser Parameter begrenzt die stattfindende Pufferung. Dieser Parameter sollte auf einen sicheren Wert festgelegt werden, wenn die XML von einer nicht vertrauenswürdigen Quelle stammt, um einen möglichen Denial-of-Service-Angriff zu vermeiden. Die SOAP-Version und die Version der WS-Adressierung der Nachricht, die der XML-Leser darstellt, müssen mit den durch den Versionsparameter angegebenen Versionen übereinstimmen.

Erstellen von Nachrichten mit dem Body Writer-Objekt

Eine CreateMessage-Überladung nimmt eine BodyWriter-Instanz an, um den Text der Nachricht zu beschreiben. Ein BodyWriter ist eine abstrakte Klasse, die abgeleitet werden kann, um das Erstellen von Nachrichtentexten anzupassen. Sie können eine eigene abgeleitete BodyWriter-Klasse erstellen, um Nachrichtentexte benutzerdefiniert zu beschreiben. Sie müssen die BodyWriter.OnWriteBodyContents-Methode überschreiben, die einen XmlDictionaryWriter annimmt; diese Methode ist für das Schreiben des Textes zuständig.

Body Writer-Objekte können gepuffert oder nicht gepuffert (gestreamt) sein. Gepufferte Body Writer-Objekte schreiben ihren Inhalt beliebig oft, während gestreamte Objekte den Inhalt nur einmal schreiben können. Die IsBuffered-Eigenschaft gibt an, ob ein Body Writer-Objekt gepuffert ist oder nicht. Sie können dies für das Body Writer-Objekt festlegen, indem Sie den geschützten BodyWriter-Konstruktor aufrufen, der einen booleschen isBuffered-Parameter annimmt. Body Writer-Objekte unterstützen das Erstellen eines gepufferten Body Writer-Objekts aus einem nicht gepufferten Body Writer-Objekt. Sie können die OnCreateBufferedCopy-Methode überschreiben, um diesen Prozess anzupassen. Standardmäßig wird ein Speicherpuffer verwendet, der die von OnWriteBodyContents zurückgegebene XML enthält. OnCreateBufferedCopy nimmt einen ganzzahligen maxBufferSize-Parameter an. Wenn Sie diese Methode überschreiben, dürfen Sie keine Puffer erstellen, die diese maximale Größe überschreiten.

Die BodyWriter-Klasse bietet die WriteBodyContents-Methode und die CreateBufferedCopy-Methode, die im Grunde einfache Wrapper um die OnWriteBodyContents-Methode bzw. die OnCreateBufferedCopy-Methode sind. Diese Methoden führen eine Zustandsprüfung durch, um sicherzustellen, dass auf ein nicht gepuffertes Body Writer-Objekt höchstens einmal zugegriffen wird. Diese Methoden werden nur direkt aufgerufen, wenn benutzerdefinierte abgeleitete Message-Klassen erstellt werden, die auf BodyWriters basieren.

Erstellen von Fehlermeldungen

Sie können bestimmte CreateMessage-Überladungen verwenden, um SOAP-Fehlermeldungen zu erstellen. Die grundlegendste dieser Überladungen nimmt ein MessageFault-Objekt an, das den Fehler beschreibt. Andere Überladungen werden aus Gründen der Benutzerfreundlichkeit bereitgestellt. Die erste solcher Überladungen nimmt einen FaultCode und eine Zeichenfolge der Ursache an und erstellt einen MessageFault mit MessageFault.CreateFault unter Verwendung dieser Informationen. Die andere Überladung nimmt eine Detailobjekt an und übergibt es auch zusammen mit dem Fehlercode und der Ursache an CreateFault. So gibt beispielsweise der folgende Vorgang einen Fehler zurück:

Public Class MyService3
    Implements IMyService

    Public Function GetData() As Message Implements IMyService.GetData
        Dim fc As New FaultCode("Receiver")
        Dim ver As MessageVersion = OperationContext.Current.IncomingMessageVersion
        Return Message.CreateMessage(ver, fc, "Bad data", "GetDataResponse")

    End Function


    Public Sub PutData(ByVal m As Message) Implements IMyService.PutData

    End Sub
End Class
public class MyService3 : IMyService
{
    public Message GetData()
    {
        FaultCode fc = new FaultCode("Receiver");
        MessageVersion ver = OperationContext.Current.IncomingMessageVersion;
            return Message.CreateMessage(ver,fc,"Bad data","GetDataResponse");
    }

    public void PutData(Message m)
    {
        // Not implemented.
    }       
}

Extrahieren von Nachrichtentextdaten

Die Message-Klasse unterstützt mehrere Methoden zum Extrahieren von Informationen aus dem Text. Diese können in die folgenden Kategorien klassifiziert werden:

  • Einmaliges Abrufen des gesamten Nachrichtentexts in einen XML-Writer. Dies wird auch als Schreiben einer Nachricht bezeichnet.

  • Laufenlassen eines XML-Readers über den Nachrichtentext. Dies ermöglicht es Ihnen, später nach Bedarf Stück für Stück auf den Nachrichtentext zuzugreifen. Dies wird auch als Lesen einer Nachricht bezeichnet.

  • Die gesamte Nachricht, einschließlich des Texts, kann in einen Puffer im Arbeitsspeicher vom MessageBuffer-Typ kopiert werden. Dies wird auch als Kopieren einer Nachricht bezeichnet.

Sie können unabhängig von der Zugriffsmethode nur einmal auf den Text einer Message zugreifen. Ein Nachrichtenobjekt verfügt über eine State-Eigenschaft, die anfänglich auf "Erstellt" festgelegt ist. Mit den drei zuvor beschriebenen Zugriffsmethoden wird der Zustand auf "Geschrieben", "Gelesen" bzw. "Kopiert" festgelegt. Darüber hinaus kann eine Close-Methode den Zustand auf "Geschlossen" festlegen, wenn der Inhalt des Nachrichtentexts nicht mehr benötigt wird. Auf den Nachrichtentext kann nur im Zustand "Erstellt" zugegriffen werden, und eine Rückkehr zu diesem Zustand ist nach einer Zustandsänderung nicht mehr möglich.

Schreiben von Nachrichten

Die WriteBodyContents-Methode schreibt den Inhalt des Texts einer bestimmten Message-Instanz in einen angegebenen XML-Writer. Die WriteBody-Methode führt den gleichen Vorgang aus. Einziger Unterschied: Der Textinhalt wird in ein entsprechendes Wrapperelement eingeschlossen (Beispiel: <soap:body>). Schließlich schreibt WriteMessage die ganze Nachricht, einschließlich des umfassenden SOAP-Umschlags und der Header. Bei deaktiviertem SOAP (Version ist MessageVersion.None) wird von allen drei Methoden der gleiche Vorgang ausgeführt: Der Inhalt des Nachrichtentexts wird geschrieben.

Beispielsweise schreibt der folgende Code der Text einer eingehenden Nachricht in eine Datei.

Public Class MyService4
    Implements IMyService
    
    Public Sub PutData(ByVal m As Message) Implements IMyService.PutData
        Dim stream As New FileStream("myfile.xml", FileMode.Create)
        Dim xdw As XmlDictionaryWriter = XmlDictionaryWriter.CreateTextWriter(stream)
        m.WriteBodyContents(xdw)
        xdw.Flush()

    End Sub
    
    
    Public Function GetData() As Message Implements IMyService.GetData
        Throw New NotImplementedException()

    End Function
End Class
public class MyService4 : IMyService
{
    public void PutData(Message m)
    {
        FileStream stream = new FileStream("myfile.xml",FileMode.Create);
        XmlDictionaryWriter xdw =
            XmlDictionaryWriter.CreateTextWriter(stream);
        m.WriteBodyContents(xdw);
        xdw.Flush();
    }

    public Message GetData()
    {
        throw new NotImplementedException();
    }
}

Zwei zusätzliche Hilfsmethoden schreiben bestimmte SOAP-Startelement-Tags. Diese Methoden haben keinen Zugriff auf den Nachrichtentext, der Nachrichtenzustand wird also nicht geändert. Dazu gehören:

Rufen Sie zum Schreiben der jeweiligen Endelement-Tags WriteEndElement auf dem entsprechenden XML-Writer auf. Diese Methoden werden selten direkt aufgerufen.

Lesen von Nachrichten

Die primäre Methode zum Lesen eines Nachrichtentexts ist das Aufrufen von GetReaderAtBodyContents. Ein XmlDictionaryReader wird zurückgegeben, mit dem Sie den Nachrichtentext lesen können. Beachten Sie, dass die Message in den Zustand "Gelesen" übergeht, sobald GetReaderAtBodyContents aufgerufen wird, und nicht, wenn Sie den XML-Reader verwenden.

Die GetBody-Methode ermöglicht Ihnen auch den Zugriff auf den Nachrichtentext als typisiertes Objekt. Intern verwendet diese Methode GetReaderAtBodyContents, daher geht die Nachricht auch in den Read-Zustand über (siehe die State-Eigenschaft).

Es wird empfohlen, die IsEmpty-Eigenschaft zu überprüfen, wobei in diesem Fall die Nachricht keinen Text enthält und GetReaderAtBodyContents eine InvalidOperationException auslöst. Wenn es sich um eine empfangene Nachricht handelt (beispielsweise um die Antwort), sollten Sie auch IsFault überprüfen, wodurch angegeben wird, ob die Nachricht einen Fehler enthält.

Die grundlegendste Überladung von GetBody deserialisiert den Nachrichtentext in eine Instanz eines Typs (angegeben durch den generischen Parameter) unter Verwendung eines DataContractSerializer, konfiguriert mit den Standardeinstellungen und mit deaktiviertem MaxItemsInObjectGraph-Kontingent. Wenn Sie ein anderes Serialisierungsmodul verwenden oder das DataContractSerializer nicht standardmäßig konfigurieren möchten, verwenden Sie die GetBody-Überladung, die ein XmlObjectSerializer annimmt.

Der folgende Code extrahiert beispielsweise Daten aus einem Nachrichtentext, der ein serialisiertes Person-Objekt enthält, und gibt den Namen der Person aus.

    Public Class MyService5
        Implements IMyService

        Public Sub PutData(ByVal m As Message) Implements IMyService.PutData
            Dim p As Person = m.GetBody(Of Person)()
            Console.WriteLine(p.name)

        End Sub


        Public Function GetData() As Message Implements IMyService.GetData
            Throw New NotImplementedException()

        End Function
    End Class
End Namespace
Namespace Samples2
    <ServiceContract()>  _
    Public Interface IMyService
        <OperationContract()>  _
        Function GetData() As Message 
        
        <OperationContract()>  _
        Sub PutData(ByVal m As Message) 
    End Interface
    <DataContract()>  _
    Public Class Person
        <DataMember()>  _
        Public name As String
        <DataMember()>  _
        Public age As Integer
    End Class
    public class MyService5 : IMyService
    {
        public void PutData(Message m)
        {
            Person p = m.GetBody<Person>();
            Console.WriteLine(p.name);
        }

        public Message GetData()
        {
            throw new NotImplementedException();
        }
      
    }
}
namespace Samples2
{
    [ServiceContract]
    public interface IMyService
    {
        [OperationContract]
        Message GetData();

        [OperationContract]
        void PutData(Message m);
    }

    [DataContract]
    public class Person
    {
        [DataMember] public string name;
        [DataMember] public int age;
    }

Kopieren einer Nachricht in einen Puffer

Manchmal ist es erforderlich, mehrmals auf den Nachrichtentext zuzugreifen, beispielsweise um die gleiche Nachricht an mehrere Ziele als Teil eines Verleger-Abonnent-Systems weiterzuleiten. In diesem Fall ist es notwendig, die gesamte Nachricht (einschließlich des Textes) im Arbeitsspeicher zu puffern. Sie können dazu CreateBufferedCopy aufrufen. Diese Methode nimmt einen ganzzahligen Parameter an, der die maximale Puffergröße darstellt, und erstellt einen Puffer mit maximal dieser Größe. Legen Sie dafür einen sicheren Wert fest, wenn die Nachricht von einer nicht vertrauenswürdigen Quelle stammt.

Der Puffer wird als MessageBuffer-Instanz zurückgegeben. Es gibt mehrere Möglichkeiten, um auf Daten im Puffer zuzugreifen. Die primäre Methode ist, CreateMessage aufzurufen, um Message-Instanzen aus dem Puffer zu erstellen.

Eine weitere Methode ist das Implementieren der IXPathNavigable-Schnittstelle, die die MessageBuffer-Klasse implementiert, um direkt auf die zugrunde liegende XML zuzugreifen. Einige CreateNavigator-Überladungen ermöglichen das Erstellen von durch ein Knotenkontingent geschützten System.Xml.XPath-Navigatoren, die die Anzahl der aufrufbaren XML-Knoten beschränken. Dies hilft, Denial-of-Service-Angriffe auf der Grundlage von längerer Verarbeitungszeit zu verhindern. Dieses Kontingent ist standardmäßig deaktiviert. Mit einigen CreateNavigator-Überladungen können Sie angeben, wie viele Leerstellen in der XML mit der XmlSpace-Enumeration behandelt werden soll, wobei der Standard XmlSpace.None ist.

Die letzte Methode zum Zugreifen auf den Inhalt eines Nachrichtenpuffers ist das Schreiben des Inhalts in einen Stream mit WriteMessage.

Das folgende Beispiel demonstriert das Arbeiten mit einem MessageBuffer: Eine eingehende Nachricht wird an mehrere Empfänger weitergeleitet und anschließend in einer Datei protokolliert. Ohne Pufferung ist dies nicht möglich, da dann der Zugriff auf den Nachrichtentext nur einmal möglich ist.

<ServiceContract()>  _
Public Class ForwardingService
    Private forwardingAddresses As List(Of IOutputChannel)

    <OperationContract()> _
    Public Sub ForwardMessage(ByVal m As Message)
        'Copy the message to a buffer.
        Dim mb As MessageBuffer = m.CreateBufferedCopy(65536)

        'Forward to multiple recipients.
        Dim channel As IOutputChannel
        For Each channel In forwardingAddresses
            Dim copy As Message = mb.CreateMessage()
            channel.Send(copy)
        Next channel

        'Log to a file.
        Dim stream As New FileStream("log.xml", FileMode.Append)
        mb.WriteMessage(stream)
        stream.Flush()

    End Sub
End Class
[ServiceContract]
public class ForwardingService
{
    private List<IOutputChannel> forwardingAddresses;

    [OperationContract]
    public void ForwardMessage (Message m)
    {
        //Copy the message to a buffer.
        MessageBuffer mb = m.CreateBufferedCopy(65536);
        
        //Forward to multiple recipients.
        foreach (IOutputChannel channel in forwardingAddresses)
        {
            Message copy = mb.CreateMessage();
            channel.Send(copy);
        }
        
        //Log to a file.
        FileStream stream = new FileStream("log.xml",FileMode.Append);
        mb.WriteMessage(stream);
        stream.Flush();
    }
}

Die MessageBuffer-Klasse verfügt über andere erwähnenswerte Member. Die Close-Methode kann aufgerufen werden, um Ressourcen freizugeben, wenn der Pufferinhalt nicht mehr benötigt wird. Die BufferSize-Eigenschaft gibt die Größe des reservierten Puffers zurück. Die MessageContentType-Eigenschaft gibt den MIME-Inhaltstyp der Nachricht zurück.

Zugreifen auf den Nachrichtentext zum Debuggen

Zum Debuggen können Sie die ToString-Methode aufrufen, um eine Darstellung der Nachricht als Zeichenfolge abzurufen. Diese Darstellung stimmt im Allgemeinen mit der Darstellung einer Nachricht überein, wenn sie mit dem Textencoder codiert worden wäre, außer dass die XML zur Lesbarkeit besser formatiert wäre. Die einzige Ausnahme ist der Nachrichtentext. Der Text kann nur einmal gelesen werden, und ToString ändert den Nachrichtenzustand nicht. Daher kann die ToString-Methode unter Umständen nicht auf den Text zugreifen, und der Nachrichtentext wird durch einen Platzhalter (z. B. "…" oder drei Punkte) ersetzt. Verwenden Sie deswegen ToString nicht zum Protokollieren von Nachrichten, wenn der Textinhalt der Nachrichten wichtig ist.

Zugreifen auf andere Nachrichtenteile

Für den Zugriff auf andere Informationen zur Nachricht als den Textinhalt werden verschiedene Eigenschaften bereitgestellt. Diese können jedoch nicht aufgerufen werden, wenn die Nachricht geschlossen wurde:

  • Die Headers-Eigenschaft stellt die Nachrichtenheader dar. Weitere Informationen finden Sie im Abschnitt "Arbeiten mit Headern" weiter unten in diesem Thema.

  • Die Properties-Eigenschaft stellt die Eigenschaften der Nachricht dar, die Teile an die Nachricht angehängter benannter Daten sind, die beim Senden der Nachricht im Allgemeinen nicht ausgegeben werden. Weitere Informationen finden Sie im Abschnitt "Arbeiten mit Eigenschaften" weiter unten in diesem Thema.

  • Die Version-Eigenschaft gibt die der Nachricht zugeordnete SOAP-Version und Version der WS-Adressierung an, oder None, wenn SOAP deaktiviert ist.

  • Die IsFault-Eigenschaft gibt true zurück, wenn die Nachricht eine SOAP-Fehlermeldung ist.

  • Die IsEmpty-Eigenschaft gibt true zurück, wenn die Nachricht keinen Text enthält.

Sie können mithilfe der GetBodyAttribute-Methode auf ein bestimmtes, mit einem bestimmten Namen und Namespace bezeichnetes Attribut im Textwrapperelement (z. B. <soap:Body>) zugreifen. Wenn ein solches Attribut nicht gefunden wurde, wird NULL zurückgegeben. Diese Methode kann nur dann aufgerufen werden, wenn sich die Message im Zustand "Erstellt" befindet (wenn noch nicht auf den Nachrichtentext zugegriffen wurde).

Arbeiten mit Headern

Eine Message kann eine beliebige Anzahl benannter XML-Fragmente enthalten, die als Header bezeichnet werden. Jedes Fragment wird normalerweise einem SOAP-Header zugeordnet. Der Zugriff auf Header erfolgt über die Headers-Eigenschaft vom Typ MessageHeaders. MessageHeaders ist eine Auflistung von MessageHeaderInfo-Objekten, und auf einzelne Header kann über die IEnumerable-Schnittstelle oder den Indexer zugegriffen werden. Im folgenden Code werden z. B. die Namen aller Header in einer Message aufgelistet.

Public Class MyService6
    Implements IMyService

    Public Sub PutData(ByVal m As Message) Implements IMyService.PutData
        Dim mhi As MessageHeaderInfo
        For Each mhi In m.Headers
            Console.WriteLine(mhi.Name)
        Next mhi

    End Sub


    Public Function GetData() As Message Implements IMyService.GetData
        Throw New NotImplementedException()

    End Function
End Class
public class MyService6 : IMyService
{
    public void PutData(Message m)
    {
        foreach (MessageHeaderInfo mhi in m.Headers)
        {
            Console.WriteLine(mhi.Name);
        }
    }

    public Message GetData()
    {
        throw new NotImplementedException();
    }
}

Hinzufügen, Entfernen und Suchen von Headern

Sie können einen neuen Header am Ende aller vorhandenen Header mit der Add-Methode hinzufügen. Sie können die Insert-Methode verwenden, um einen Header an einem bestimmten Index einzufügen. Vorhandene Header werden für das eingefügte Element verschoben. Header werden nach ihrem Index geordnet, dabei ist der erste verfügbare Index 0. Sie können mithilfe der verschiedenen CopyHeadersFrom-Methodenüberladungen Header aus einer anderen Message- oder MessageHeaders-Instanz hinzufügen. Einige Überladungen kopieren einen einzelnen Header, während andere alle Header kopieren. Mit der Clear-Methode werden alle Header entfernt. Die RemoveAt-Methode entfernt einen Header an einem bestimmten Index (alle nachfolgenden Header werden verschoben). Die RemoveAll-Methode entfernt alle Header mit einem bestimmten Namen und Namespace.

Rufen Sie mit der FindHeader-Methode einen bestimmten Header ab. Diese Methode nimmt den Namen und Namespace des zu suchenden Headers an, und gibt seinen Index zurück. Wenn der Header mehrmals auftritt, wird eine Ausnahme ausgelöst. Wenn der Header nicht gefunden wurde, wird -1 zurückgegeben.

Im SOAP-Headermodell können Header einen Actor-Wert aufweisen, der den gewünschten Empfänger des Headers angibt. Die grundlegendste FindHeader-Überladung sucht nur Header, die für den letzten Empfänger der Nachricht vorgesehen sind. Mit einer anderen Überladung können Sie jedoch angeben, welche Actor-Werte in der Suche enthalten sind. Weitere Informationen finden Sie unter der SOAP-Spezifikation.

Eine CopyTo-Methode wird für das Kopieren von Headern aus einer MessageHeaders-Auflistung zu einem Array von MessageHeaderInfo-Objekten bereitgestellt.

Für den Zugriff auf die XML-Daten in einem Header können Sie GetReaderAtHeader aufrufen und einen XML-Leser für den Headerindex zurückgeben. Verwenden Sie zum Deserialisieren des Headerinhalts in ein Objekt GetHeader oder eine der anderen Überladungen. Die grundlegendsten Überladungen deserialisieren Header mit dem DataContractSerializer, der standardmäßig konfiguriert wurde. Wenn Sie ein anderes Serialisierungsprogramm oder eine andere Konfiguration von DataContractSerializer verwenden möchten, nutzen Sie eine der Überladungen, die ein XmlObjectSerializer akzeptieren. Einige Überladungen akzeptieren auch den Headernamen, Namespace und optional eine Liste von Actor-Werte anstelle eines Index; dies ist eine Kombination von FindHeader und GetHeader.

Arbeiten mit Eigenschaften

Eine Message-Instanz kann eine beliebige Anzahl von benannten Objekten beliebiger Typen enthalten. Auf diese Auflistung wird über die Properties-Eigenschaft vom Typ MessageProperties zugegriffen. Die Auflistung implementiert die IDictionary-Schnittstelle und fungiert als Zuordnung von String zu Object. Normalerweise werden Eigenschaftswerte einem Teil der Nachricht nicht direkt zugeordnet, sie bieten vielmehr verschiedene Nachrichtenverarbeitungshinweise für die Kanäle im WCF-Kanalstapel oder für das CopyTo-Dienstframework. Ein Beispiel finden Sie unter Datenübertragungsarchitektur - Übersicht.

Erben von der Meldungsklasse

Erstellen Sie eine von der Message-Klasse abgeleitete Klasse, wenn die mit CreateMessage erstellten integrierten Nachrichtentypen nicht den Anforderungen entsprechen.

Definieren des Nachrichtentextinhalts

Für den Zugriff auf Daten innerhalb eines Nachrichtentexts gibt es drei grundlegende Verfahren: Schreiben, Lesen und Kopieren in einen Puffer. Diese Verfahren führen im Endeffekt dazu, dass die OnWriteBodyContents-Methode, die OnGetReaderAtBodyContents-Methode bzw. die OnCreateBufferedCopy-Methode in der abgeleiteten Message-Klasse aufgerufen wird. Die Message-Basisklasse stellt sicher, dass für jede Message-Instanz nur eine dieser Methoden aufgerufen wird und dieser Vorgang jeweils nur einmal stattfindet. Die Basisklasse stellt auch sicher, dass die Methoden nicht für eine geschlossene Nachricht aufgerufen werden. Es ist nicht erforderlich, den Nachrichtenzustand in der Implementierung zu verfolgen.

OnWriteBodyContents ist eine abstrakte Methode und muss implementiert werden. Die grundlegendste Weise zum Definieren des Textinhalts der Nachricht ist, mit dieser Methode zu schreiben. Zum Beispiel enthält die folgende Nachricht 100.000 Zufallszahlen von 1 bis 20.

Public Class RandomMessage
    Inherits Message

    Protected Overrides Sub OnWriteBodyContents( _
            ByVal writer As XmlDictionaryWriter)
        Dim r As New Random()
        Dim i As Integer
        For i = 0 To 99999
            writer.WriteStartElement("number")
            writer.WriteValue(r.Next(1, 20))
            writer.WriteEndElement()
        Next i

    End Sub
    ' Code omitted.
public class RandomMessage : Message
{
    override protected  void  OnWriteBodyContents(XmlDictionaryWriter writer)
    {
        Random r = new Random();
        for (int i = 0; i <100000; i++)
        {
            writer.WriteStartElement("number");
            writer.WriteValue(r.Next(1,20));
            writer.WriteEndElement();
        }
    }    
    //code omitted

Die OnGetReaderAtBodyContents-Methode und die OnCreateBufferedCopy-Methode verfügen über Standardimplementierungen, die in den meisten Fällen funktionieren. Die Standardimplementierungen rufen OnWriteBodyContents auf, speichern die Ergebnisse im Puffer und arbeiten mit dem resultierenden Puffer. In einigen Fällen genügt dies möglicherweise nicht. In vorhergehenden Beispiel führt das Lesen der Nachricht dazu, dass 100.000 XML-Elemente im Puffer gespeichert werden, was unter Umständen nicht wünschenswert ist. Es kann empfehlenswert sein, OnGetReaderAtBodyContents zu überschreiben, um eine benutzerdefinierte abgeleitete XmlDictionaryReaderKlasse zurückzugeben, die Zufallszahlen bereitstellt. Sie können dann OnWriteBodyContents überschreiben, um den von der OnGetReaderAtBodyContents-Eigenschaft zurückgegebenen Leser zu verwenden, wie im folgenden Beispiel dargestellt.

    Public Overrides ReadOnly Property Headers() As MessageHeaders
        Get
            Throw New Exception("The method or operation is not implemented.")
        End Get
    End Property

    Public Overrides ReadOnly Property Properties() As MessageProperties
        Get
            Throw New Exception("The method or operation is not implemented.")
        End Get
    End Property

    Public Overrides ReadOnly Property Version() As MessageVersion
        Get
            Throw New Exception("The method or operation is not implemented.")
        End Get
    End Property
End Class

Public Class RandomMessage2
    Inherits Message
    
    Protected Overrides Function OnGetReaderAtBodyContents() As XmlDictionaryReader 
        Return New RandomNumbersXmlReader()
    
    End Function
    
    
    Protected Overrides Sub OnWriteBodyContents(ByVal writer As XmlDictionaryWriter) 
        Dim xdr As XmlDictionaryReader = OnGetReaderAtBodyContents()
        writer.WriteNode(xdr, True)
    
    End Sub
    
    Public Overrides ReadOnly Property Headers() As MessageHeaders 
        Get
            Throw New Exception("The method or operation is not implemented.")
        End Get
    End Property 
    
    Public Overrides ReadOnly Property Properties() As MessageProperties 
        Get
            Throw New Exception("The method or operation is not implemented.")
        End Get
    End Property 
    
    Public Overrides ReadOnly Property Version() As MessageVersion 
        Get
            Throw New Exception("The method or operation is not implemented.")
        End Get
    End Property
End Class

Public Class RandomNumbersXmlReader
    Inherits XmlDictionaryReader
    'code to serve up 100000 random numbers in XML form omitted
    public override MessageHeaders Headers
    {
        get { throw new Exception("The method or operation is not implemented."); }
    }

    public override MessageProperties Properties
    {
        get { throw new Exception("The method or operation is not implemented."); }
    }

    public override MessageVersion Version
    {
        get { throw new Exception("The method or operation is not implemented."); }
    }
}

public class RandomMessage2 : Message
{
    override protected XmlDictionaryReader OnGetReaderAtBodyContents()
    {
    return new RandomNumbersXmlReader();
    }
    
    override protected void OnWriteBodyContents(XmlDictionaryWriter writer)
    {
        XmlDictionaryReader xdr = OnGetReaderAtBodyContents();
        writer.WriteNode(xdr, true); 
    }    
    public override MessageHeaders Headers
    {
        get { throw new Exception("The method or operation is not implemented."); }
    }
    
    public override MessageProperties Properties
    {
        get { throw new Exception("The method or operation is not implemented."); }
    }
    
    public override MessageVersion Version
    {
        get { throw new Exception("The method or operation is not implemented."); }
    }
}

public class RandomNumbersXmlReader : XmlDictionaryReader
{
    //code to serve up 100000 random numbers in XML form omitted

Auf ähnliche Weise können Sie OnCreateBufferedCopy überschreiben, um eine eigene abgeleitete MessageBuffer-Klasse zurückzugeben.

Zusätzlich zum Bereitstellen von Nachrichtentextinhalt muss die abgeleitete Nachrichtenklasse auch die Version-Eigenschaft, die Headers-Eigenschaft und die Properties-Eigenschaft überschreiben.

Beachten Sie, dass beim Erstellen der Kopie einer Nachricht die Kopie die Nachrichtenheader aus dem Original verwendet.

Andere Member, die überschrieben werden können

Sie können die OnWriteStartEnvelope-Methode, die OnWriteStartHeaders-Methode und die OnWriteStartBody-Methode überschreiben, um anzugeben, wie der SOAP-Umschlag, die SOAP-Header und die SOAP-Textelement-Starttags geschrieben werden. Diese entsprechen normalerweise <soap:Envelope><soap:Header>, <soap:Body> und . Diese Methoden sollten normalerweise nichts schreiben, wenn die Version-Eigenschaft MessageVersion.None zurückgibt.

ms734675.note(de-de,VS.100).gifHinweis:
Die Standardimplementierung von OnGetReaderAtBodyContents ruft OnWriteStartEnvelope und OnWriteStartBody auf, bevor OnWriteBodyContents aufgerufen wird und die Ergebnisse im Puffer gespeichert werden. Header werden nicht geschrieben.

Überschreiben Sie die OnWriteMessage-Methode, um das Verfahren zu ändern, wie die gesamte Nachricht aus den verschiedenen Teilen erstellt wird. Die OnWriteMessage-Methode wird aus WriteMessage und aus der OnCreateBufferedCopy-Standardimplementierung aufgerufen. Beachten Sie, dass das Überschreiben von WriteMessage keine empfohlene Vorgehensweise ist. Es ist besser, die entsprechenden On-Methoden zu überschreiben, z. B OnWriteStartEnvelope, OnWriteStartHeaders und OnWriteBodyContents.

Überschreiben Sie OnBodyToString, um zu überschreiben, wie der Nachrichtentext während des Debuggens dargestellt wird. Der Standard ist die Darstellung als drei Punkte ("…"). Diese Methode kann mehrfach ausgerufen werden, wenn der Nachrichtenzustand nicht "Geschlossen" lautet. Eine Implementierung dieser Methode sollte nie eine Aktion verursachen, die nur einmal ausgeführt werden muss (wie das Lesen eines Vorwärtsstreams).

Überschreiben Sie die OnGetBodyAttribute-Methode, um den Zugriff auf Attribute im SOAP-Textelement zuzulassen. Diese Methode kann beliebig oft aufgerufen werden, der Message-Basistyp stellt jedoch sicher, dass sie nur dann aufgerufen wird, wenn der Zustand der Nachricht "Erstellt" lautet. Es ist nicht erforderlich, den Zustand in einer Implementierung zu überprüfen. Die Standardimplementierung gibt immer NULL zurück, was bedeutet, dass im Textelement keine Attribute vorhanden sind.

Soll das Message-Objekt eine spezielle Bereinigung ausführen, wenn der Nachrichtentext nicht mehr benötigt wird, können Sie OnClose überschreiben. Bei der Standardimplementierung wird keine Aktion ausgeführt.

Die IsEmpty-Eigenschaft und die IsFault-Eigenschaft können überschrieben werden. Standardmäßig geben beide false zurück.