Používání třídy Message

Třída Message je zásadní pro Windows Communication Foundation (WCF). Veškerá komunikace mezi klienty a službami nakonec vede k tomu, že jsou instance Message odesílány a přijímány.

Obvykle byste s tou třídou Message nepracovali přímo. Místo toho se k popisu příchozích a odchozích zpráv používají konstrukty modelu služby WCF, jako jsou kontrakty dat, kontrakty zpráv a kontrakty operací. V některých pokročilých scénářích ale můžete programovat přímo pomocí Message třídy. Můžete například chtít použít Message třídu:

  • Pokud potřebujete alternativní způsob vytváření obsahu odchozích zpráv (například vytvoření zprávy přímo ze souboru na disku) místo serializace objektů rozhraní .NET Framework.

  • Pokud potřebujete alternativní způsob použití obsahu příchozích zpráv (například pokud chcete použít transformaci XSLT na nezpracovaný obsah XML) místo deserializace do objektů rozhraní .NET Framework.

  • Pokud potřebujete zpracovávat zprávy obecným způsobem bez ohledu na obsah zpráv (například při směrování nebo přeposílání zpráv při vytváření směrovače, nástroje pro vyrovnávání zatížení nebo systému publikování a odběru).

Před použitím Message třídy se seznamte s architekturou přenosu dat WCF v přehledu architektury přenosu dat.

A Message je kontejner pro obecné účely pro data, ale jeho návrh úzce sleduje návrh zprávy v protokolu SOAP. Stejně jako v protokolu SOAP má zpráva jak text zprávy, tak záhlaví. Tělo zprávy obsahuje skutečná uživatelská data, zatímco hlavičky obsahují další pojmenované datové kontejnery. Pravidla pro čtení a zápis těla a záhlaví se liší, například záhlaví se vždy ukládají do paměti a mohou být přístupná v libovolném pořadí, zatímco tělo může být přečteno pouze jednou a může být streamováno. Při použití protokolu SOAP se text zprávy mapuje na tělo protokolu SOAP a záhlaví zprávy se mapují na hlavičky SOAP.

Použití třídy zpráv v operacích

Třídu můžete použít Message jako vstupní parametr operace, návratovou hodnotu operace nebo obojí. Pokud Message se používá kdekoli v operaci, platí následující omezení:

  • Operace nemůže mít žádné out parametry ani ref parametry.

  • Nemůže existovat více než jeden input parametr. Pokud je parametr k dispozici, musí to být buď "Message" nebo typ kontraktu zprávy.

  • Návratový typ musí být buď void, Messagenebo typ kontraktu zprávy.

Následující příklad kódu obsahuje platný kontrakt operace.

[ServiceContract]
public interface IMyService
{
    [OperationContract]
    Message GetData();

    [OperationContract]
    void PutData(Message m);
}
<ServiceContract()> _
Public Interface IMyService
    <OperationContract()> _
    Function GetData() As Message

    <OperationContract()> _
    Sub PutData(ByVal m As Message)
End Interface

Vytváření základních zpráv

Třída Message poskytuje statické tovární metody k vytvoření základních zpráv.

Všechna CreateMessage přetížení přebírají parametr typu MessageVersion, který označuje verze SOAP a WS-Addressing, které se mají použít pro zprávu. Pokud chcete použít stejné verze protokolu jako příchozí zpráva, můžete použít IncomingMessageVersion vlastnost u OperationContext instance získané z Current vlastnosti. Většina CreateMessage přetížení má také řetězcový parametr, který označuje akci SOAP, která se má použít pro zprávu. Verzi lze nastavit na None, aby se zakázalo generování obálky SOAP; zpráva se skládá pouze z těla.

Vytváření zpráv z objektů

Nejzásadnější CreateMessage přetížení, které přijímá pouze verzi a akci, vytvoří zprávu s prázdným tělem. Další přetížení přebírá další Object parametr; tím se vytvoří zpráva, jejíž tělo je serializovaná reprezentace daného objektu. DataContractSerializer Použijte výchozí nastavení pro serializaci. Pokud chcete použít jiný serializátor, nebo chcete DataContractSerializer nakonfigurovat jinak, použijte přetížení CreateMessage, které také přijímá parametr XmlObjectSerializer.

Pokud chcete například vrátit objekt ve zprávě, můžete použít následující kód.

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;
}
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

Vytváření zpráv ze čteček XML

Existují přetížení, která přebírají CreateMessage nebo XmlReader místo objektu. V tomto případě obsahuje text zprávy XML, který je výsledkem čtení z předané čtečky XML. Například následující kód vrátí zprávu s obsahem textu načteným ze souboru XML.

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.
    }
}
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

Kromě toho existují CreateMessage přetížení, která přebírají XmlReader nebo XmlDictionaryReader a která představují celou zprávu, a nejen tělo. Tato přetížení také přebírají celočíselnou maxSizeOfHeaders hodnotu parametru. Hlavičky se vždy ukládají do paměti, jakmile se zpráva vytvoří, a tento parametr omezuje množství ukládání do vyrovnávací paměti, které probíhá. Tento parametr je důležité nastavit na bezpečnou hodnotu, pokud XML pochází z nedůvěryhodného zdroje, aby se zmírnila možnost útoku odmítnutí služby. Verze SOAP a WS-Adresování zprávy, kterou čtečka XML představuje, musí odpovídat verzím uvedeným pomocí parametru verze.

Vytváření zpráv pomocí bodyWriter

Jedno CreateMessage přetížení přebírá BodyWriter instanci k popisu textu zprávy. A BodyWriter je abstraktní třída, která může být odvozena pro přizpůsobení způsobu vytváření těla zprávy. Můžete vytvořit vlastní BodyWriter odvozenou třídu, která popisuje těla zpráv vlastním způsobem. Musíte přepsat metodu BodyWriter.OnWriteBodyContents, která přebírá XmlDictionaryWriter; tato metoda je zodpovědná za výpis těla.

Zapisovače mohou být ukládány do vyrovnávací paměti nebo neukládány do vyrovnávací paměti (streamovány). Zapisovače s vyrovnávací pamětí mohou svůj obsah zapsat libovolně mnohokrát, zatímco streamovaní mohou obsah zapsat pouze jednou. Vlastnost IsBuffered označuje, zda je zapisovač těla uložen do vyrovnávací paměti, nebo ne. Můžete to nastavit pro zapisovač obsahu voláním chráněného BodyWriter konstruktoru, který přijímá isBuffered logický parametr. Zapisovače těla podporují vytvoření vyrovnávacího zapisovače těla z nevyrovnávacího zapisovače těla. Můžete přepsat metodu OnCreateBufferedCopy pro přizpůsobení tohoto procesu. Ve výchozím nastavení se používá vyrovnávací paměť v paměti, která obsahuje kód XML vrácený OnWriteBodyContents . OnCreateBufferedCopy přebírá celočíselnou hodnotu. Pokud tuto metodu maxBufferSize přepíšete, nesmíte vytvářet vyrovnávací paměti větší než tato maximální velikost.

Třída BodyWriter poskytuje metody WriteBodyContents a CreateBufferedCopy, které jsou v podstatě tenké obálky kolem metod OnWriteBodyContents a OnCreateBufferedCopy v uvedeném pořadí. Tyto metody provádějí kontrolu stavu, aby se zajistilo, že se k zapisovači obsahu, který není uložený ve vyrovnávací paměti, nepřistupuje více než jednou. Tyto metody se volají přímo pouze při vytváření vlastních Message odvozených tříd založených na BodyWriters.

Vytváření chybových zpráv

K vytvoření chybových zpráv SOAP můžete použít určitá CreateMessage přetížení. Nejzásadnější z nich je objekt MessageFault , který popisuje chybu. Další přetížení funkcí jsou k dispozici pro zjednodušení. První takové přetížení vezme FaultCode a důvodový řetězec a vytvoří MessageFault pomocí MessageFault.CreateFault na základě těchto informací. Druhé přetížení přijímá objekt podrobností a také jej předává CreateFault spolu s chybovým kódem a důvodem. Například následující operace vrátí chybu.

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.
    }
}
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

Extrahování dat textu zprávy

Třída Message podporuje různé způsoby extrakce informací z jejího obsahu. Tyto kategorie je možné klasifikovat do následujících kategorií:

  • Získání celého textu zprávy napsaného najednou do zapisovače XML. To se označuje jako zápis zprávy.

  • Získání čtečky XML nad textem zprávy To vám umožní později získat přístup k části textu zprávy podle potřeby. To se označuje jako čtení zprávy.

  • Celou zprávu, včetně jejího textu, lze zkopírovat do vyrovnávací paměti typu MessageBuffer. To se označuje jako kopírování zprávy.

K textu Message jen jednou se dostanete bez ohledu na to, jak se k němu přistupuje. Objekt zprávy má State vlastnost, která je původně nastavena na Vytvořeno. Tři metody přístupu popsané v předchozím seznamu nastavují stav Zapsaný, Přečtený a Kopírovaný. Kromě toho Close může metoda nastavit stav Uzavřeno, pokud už není potřeba obsah textu zprávy. Text zprávy je přístupný pouze ve stavu Vytvoření a neexistuje způsob, jak se po změně stavu vrátit zpět do stavu Vytvoření.

Psaní zpráv

Metoda WriteBodyContents(XmlDictionaryWriter) zapíše základní obsah dané Message instance danému zapisovači XML. Metoda WriteBody dělá totéž, s tím rozdílem, že uzavře obsah těla do příslušného elementu obálky (například <soap:body>). WriteMessage Nakonec zapíše celou zprávu, včetně celé obálky SOAP a záhlaví. Pokud je protokol SOAP vypnutý (Version je MessageVersion.None), všechny tři metody dělají totéž: zapisují obsah textu zprávy.

Například následující kód zapíše text příchozí zprávy do souboru.

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();
    }
}
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

Dvě další pomocné metody zapisují určité počáteční značky elementů protokolu SOAP. Tyto metody nemají přístup k textu zprávy, a proto nemění stav zprávy. Tady jsou některé z nich:

  • WriteStartBody zapíše počáteční základní prvek, například <soap:Body>.

  • WriteStartEnvelope zapíše prvek počáteční obálky, například <soap:Envelope>.

Chcete-li napsat odpovídající značky koncových elementů, zavolejte WriteEndElement na odpovídajícím zapisovači XML. Tyto metody se přímo volají zřídka.

Čtení zpráv

Primárním způsobem čtení textu zprávy je volání GetReaderAtBodyContents. Dostanete zpět XmlDictionaryReader, pomocí kterého si můžete přečíst tělo zprávy. Všimněte si, že Message přechází do režimu čtení, jakmile je zavolán GetReaderAtBodyContents, a ne při použití vrácené čtečky XML.

Metoda GetBody také umožňuje přístup k tělu zprávy jako typovaný objekt. Interně tato metoda používá GetReaderAtBodyContents, a proto také převádí stav zprávy do stavu Read (viz State vlastnost).

Je vhodné zkontrolovat IsEmpty vlastnost, v takovém případě je text zprávy prázdný a GetReaderAtBodyContents vyvolá chybu InvalidOperationException. Pokud se jedná o přijatou zprávu (například odpověď), můžete také zkontrolovat IsFault, což označuje, jestli zpráva obsahuje chybu.

Nejzákladnější přetížení GetBody deserializuje tělo zprávy do instance typu určeného obecným parametrem, přičemž používá DataContractSerializer nakonfigurovaný s výchozími nastaveními a s deaktivovaným limitem MaxItemsInObjectGraph. Chcete-li použít jiný serializační modul nebo nakonfigurovat DataContractSerializer jiným způsobem než výchozí, použijte GetBody přetížení, které přebírá XmlObjectSerializer.

Například následující kód extrahuje data z textu zprávy, která obsahuje serializovaný Person objekt a vytiskne jméno osoby.

    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;
    }
    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

Kopírování zprávy do vyrovnávací paměti

Někdy je nutné získat přístup k textu zprávy více než jednou, například pro přeposlání stejné zprávy do více cílů jako součást systému pro předplatitele vydavatele. V tomto případě je nutné uložit do vyrovnávací paměti celou zprávu (včetně těla). Můžete to udělat voláním CreateBufferedCopy(Int32). Tato metoda přebírá celočíselný parametr, který představuje maximální velikost vyrovnávací paměti, a vytvoří buffer, který této velikosti nepřekročí. Pokud zpráva pochází z nedůvěryhodného zdroje, je důležité ji nastavit na bezpečnou hodnotu.

Vyrovnávací paměť je vrácena jako MessageBuffer instance. K datům ve vyrovnávací paměti můžete přistupovat několika způsoby. Primární způsob je volat CreateMessage, aby se vytvořily instance Message z vyrovnávací paměti.

Dalším způsobem, jak získat přístup k datům ve vyrovnávací paměti, je implementovat IXPathNavigable rozhraní, které MessageBuffer třída implementuje pro přímý přístup k podkladovému XML. Některá CreateNavigator přetížení umožňují vytvářet System.Xml.XPath navigátory chráněné uzlovou kvótou, což omezuje počet uzlů, které mohou být navštíveny. To pomáhá zabránit útokům na dostupnost služby na základě dlouhé doby zpracování. Tato uvozovka je ve výchozím nastavení zakázaná. Některá CreateNavigator přetížení umožňují určit, jak se mají zpracovávat mezery v XML pomocí enumerace XmlSpace s výchozí hodnotou XmlSpace.None.

Posledním způsobem, jak získat přístup k obsahu vyrovnávací paměti zprávy, je zapsáním jeho obsahu do datového proudu pomocí WriteMessage.

Následující příklad ukazuje proces práce s MessageBuffer: příchozí zpráva se přeposílá více příjemcům a pak se zapíše do protokolu do souboru. Bez ukládání do vyrovnávací paměti to není možné, protože text zprávy je pak přístupný pouze jednou.

[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();
    }
}
<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

Třída MessageBuffer má další členy, které stojí za zmínku. Metodu Close můžete zavolat k uvolnění prostředků, když již není potřeba obsah vyrovnávací paměti. Vlastnost BufferSize vrátí velikost přidělené vyrovnávací paměti. Vlastnost MessageContentType vrátí typ obsahu MIME zprávy.

Přístup k textu zprávy pro ladění

Pro účely ladění můžete volat metodu ToString, abyste získali reprezentaci zprávy jako řetězec. Tato reprezentace obecně odpovídá způsobu, jakým by zpráva vypadala na drátu, pokud by byla kódována pomocí textového kodéru, s tím rozdílem, že XML by byl lépe naformátovaný pro čitelnost člověka. Jedinou výjimkou je text zprávy. Tělo může být přečteno pouze jednou a ToString nezmění stav zprávy. ToString Proto metoda nemusí mít přístup k textu a může nahradit zástupný symbol (například "..." nebo tři tečky) místo textu zprávy. Proto nepoužívejte ToString k protokolování zpráv, pokud je důležitý základní obsah zpráv.

Přístup k jiným částem zpráv

Různé vlastnosti jsou k dispozici pro přístup k informacím o jiné zprávě, než je její základní obsah. Po zavření zprávy se ale nedají volat:

  • Vlastnost Headers představuje záhlaví zprávy. Podívejte se na část Práce se záhlavími dále v tomto tématu.

  • Vlastnost Properties představuje vlastnosti zprávy, které jsou části pojmenovaných dat připojené ke zprávě, které se obvykle nevygenerují při odeslání zprávy. Viz část "Práce s vlastnostmi" dále v tomto tématu.

  • Tato Version vlastnost označuje verzi SOAP a WS-Adresování přidruženou ke zprávě nebo None pokud je protokol SOAP zakázán.

  • Tato IsFault vlastnost se vrátí true , pokud je zpráva chybovou zprávou SOAP.

  • Vlastnost IsEmpty vrátí true , pokud je zpráva prázdná.

Tuto metodu GetBodyAttribute(String, String) můžete použít pro přístup ke konkrétnímu atributu elementu body wrapper (například <soap:Body>) identifikovaného konkrétním názvem a oborem názvů. Pokud se takový atribut nenajde, null vrátí se. Tuto metodu lze volat pouze v případě, že je Message ve stavu Vytvořeno (pokud text zprávy ještě nebyl zpřístupněn).

Práce se záhlavími

A Message může obsahovat libovolný počet pojmenovaných fragmentů XML, označovaných jako záhlaví. Každý fragment se obvykle mapuje na hlavičku SOAP. Hlavičky jsou přístupné přes vlastnost typu HeadersMessageHeaders. MessageHeaders je kolekce MessageHeaderInfo objektů a k jednotlivým záhlavím lze přistupovat prostřednictvím tohoto IEnumerable rozhraní nebo prostřednictvím indexeru. Například následující kód uvádí názvy všech hlaviček v souboru Message.

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();
    }
}
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

Přidávání, odebírání a hledání hlaviček

Novou hlavičku můžete přidat na konec všech existujících hlaviček pomocí Add metody. Metodu Insert můžete použít k vložení hlavičky do určitého indexu. Existující záhlaví se upraví pro vloženou položku. Záhlaví jsou seřazená podle indexu a první dostupný index je 0. Pomocí různých přetížení metody CopyHeadersFrom můžete přidat hlavičky z jiné instance Message nebo MessageHeaders. Některá přetížení kopírují jednu jednotlivou hlavičku, zatímco jiné kopírují všechny. Metoda Clear odebere všechny hlavičky. Metoda RemoveAt odebere záhlaví v určitém indexu (posune všechna záhlaví za ním). Metoda RemoveAll odebere všechny hlavičky s konkrétním názvem a jmenným prostorem.

Načtěte konkrétní hlavičku pomocí metody FindHeader. Tato metoda vezme jméno a obor názvů hlavičky, kterou je třeba vyhledat, a vrátí její index. Pokud se záhlaví vyskytuje více než jednou, vyvolá se výjimka. Pokud se hlavička nenajde, vrátí hodnotu -1.

V modelu hlaviček PROTOKOLU SOAP můžou mít Actor hlavičky hodnotu, která určuje zamýšlený příjemce hlavičky. Nejzákladnější FindHeader přetížení hledá pouze hlavičky určené pro konečného příjemce zprávy. Jiné přetížení však umožňuje určit, které Actor hodnoty jsou zahrnuty do vyhledávání. Další informace najdete ve specifikaci PROTOKOLU SOAP.

Metoda CopyTo(MessageHeaderInfo[], Int32) je poskytována ke kopírování hlaviček z MessageHeaders kolekce do pole MessageHeaderInfo objektů.

Pokud chcete získat přístup k datům XML v hlavičce, můžete volat GetReaderAtHeader a vracet čtečku XML pro konkrétní index hlavičky. Chcete-li deserializovat obsah záhlaví do objektu, použijte GetHeader<T>(Int32) nebo jednu z dalších alternativ. Nejzákladnější přetížení deserializují hlavičky pomocí DataContractSerializer, které je nakonfigurováno výchozím způsobem. Chcete-li použít jiný serializátor nebo jinou konfiguraci DataContractSerializer, zvolte jedno z přetížení, která přijímají XmlObjectSerializer. Existují také přetížení, která přebírají název hlavičky, obor názvů a volitelně seznam Actor hodnot místo indexu; jedná se o kombinaci FindHeader a GetHeader.

Práce s vlastnostmi

Instance Message může obsahovat libovolný počet pojmenovaných objektů libovolných typů. Tato kolekce je přístupná prostřednictvím Properties vlastnosti typu MessageProperties. Kolekce implementuje IDictionary<TKey,TValue> rozhraní a funguje jako mapování z String na Object. Hodnoty vlastností se obvykle nemapují přímo na žádnou část zprávy na síti, ale spíše poskytují různá vodítka ke zpracování zpráv pro různé kanály v kanálovém zásobníku WCF nebo pro CopyTo(MessageHeaderInfo[], Int32) rozhraní služby. Příklad najdete v tématu Přehled architektury přenosu dat.

Dědění z třídy Message

Pokud předdefinované typy zpráv vytvořené pomocí CreateMessage nesplňují vaše požadavky, vytvořte třídu odvozenou od Message třídy.

Definování obsahu textu zprávy

Existují tři hlavní techniky pro přístup k datům v textu zprávy: zápis, čtení a kopírování do vyrovnávací paměti. Tyto operace nakonec vedou k volání metod OnWriteBodyContents, OnGetReaderAtBodyContents a OnCreateBufferedCopy, a to v uvedeném pořadí na odvozené třídě Message. Základní Message třída zaručuje, že pro každou Message instanci je volána pouze jedna z těchto metod a že není volána více než jednou. Základní třída také zajišťuje, že metody nejsou volány na uzavřenou zprávu. Ve vaší implementaci není nutné sledovat stav zprávy.

OnWriteBodyContents je abstraktní metoda a musí být implementována. Nejzásadnější způsob, jak definovat obsah zprávy, je psát pomocí této metody. Například následující zpráva obsahuje 100 000 náhodných čísel od 1 do 20.

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…
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.

Ve výchozím nastavení mají metody OnGetReaderAtBodyContents() a OnCreateBufferedCopy implementace, které fungují ve většině případů. Výchozí implementace volají OnWriteBodyContents, ukládají výsledky do vyrovnávací paměti a pracují s ní. V některých případech to ale nemusí stačit. Čtení zprávy v předchozím příkladu vede k ukládání do vyrovnávací paměti 100 000 elementů XML, což nemusí být žádoucí. Možná budete chtít přepsat OnGetReaderAtBodyContents() tak, aby vracel vlastní třídu XmlDictionaryReader odvozenou, která slouží k obsluze náhodných čísel. Potom můžete přepsat OnWriteBodyContents pro použití čtečky, kterou metoda OnGetReaderAtBodyContents() vrátí, jak je znázorněno v následujícím příkladu.

    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…

    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

Podobně můžete chtít přepsat OnCreateBufferedCopy, abyste vrátili vlastní odvozenou třídu MessageBuffer.

Kromě poskytování obsahu zprávy musí odvozená třída zprávy také přepsat vlastnosti Version, Headers a Properties.

Všimněte si, že pokud vytvoříte kopii zprávy, kopie použije záhlaví zprávy z původní verze.

Ostatní členové, které lze přepsat

Můžete přepsat metody OnWriteStartEnvelope, OnWriteStartHeaders a OnWriteStartBody, abyste určili, jak se zapisují počáteční značky obálky SOAP, hlaviček SOAP a základního elementu těla SOAP. Ty obvykle odpovídají <soap:Envelope>, <soap:Header> a <soap:Body>. Tyto metody by obvykle neměly zapsat nic, pokud Version vlastnost vrátí None.

Poznámka:

Výchozí implementace OnGetReaderAtBodyContents volá OnWriteStartEnvelope a OnWriteStartBody před voláním OnWriteBodyContents a ukládáním výsledků do vyrovnávací paměti. Hlavičky se nezapisují.

Přepište metodu OnWriteMessage , která změní způsob, jakým je celá zpráva vytvořena z různých částí. Metoda OnWriteMessage je volána z WriteMessage a z výchozí OnCreateBufferedCopy implementace. Upozorňujeme, že přepsání WriteMessage není považováno za osvědčený postup. Je lepší přepsat vhodné On metody (například OnWriteStartEnvelope, OnWriteStartHeaders, a OnWriteBodyContents.

Přepsáním OnBodyToString můžete přepsat způsob znázornění textu zprávy během ladění. Výchozí hodnota je, že se to zobrazuje třemi tečkami (…). Všimněte si, že tuto metodu lze volat vícekrát, pokud je stav zprávy cokoli jiného než Uzavřeno. Implementace této metody by nikdy neměla způsobit žádnou akci, která musí být provedena pouze jednou (například čtení z dopředného datového proudu).

Přepište metodu OnGetBodyAttribute tak, aby byl povolen přístup k atributům v elementu těla SOAP. Tuto metodu lze volat libovolný početkrát, ale Message základní typ zaručuje, že je volána pouze tehdy, když je zpráva ve stavu Created. Není nutné kontrolovat stav v implementaci. Výchozí implementace vždy vrátí null, což označuje, že neexistují žádné atributy v elementu body.

Pokud váš objekt Message musí provést jakékoli zvláštní vyčištění, jakmile text zprávy již není potřeba, můžete přepsat OnClose. Výchozí implementace nic nedělá.

Vlastnosti IsEmpty a IsFault lze přepsat. Ve výchozím nastavení vrátí obě hodnoty false.