Sdílet prostřednictvím


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 Message odesílání a přijetí instancí.

Obvykle byste s třídou nepracují Message 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í. Text zprávy obsahuje skutečná data datové části, zatímco záhlaví obsahují další pojmenované datové kontejnery. Pravidla pro čtení a zápis textu a záhlaví se liší, například záhlaví se vždy ukládají do vyrovnávací paměti a můžou 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 zpráva 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é CreateMessage metody továrny, které můžete použít k vytváření základních zpráv.

Všechna CreateMessage přetížení přebírají parametr verze typu MessageVersion , který označuje verze SOAP a WS-Addressing verze, 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 je možné nastavit tak, aby None se zakázalo generování obálky SOAP. Zpráva se skládá pouze z textu.

Vytváření zpráv z objektů

Nejzásadnější CreateMessage přetížení, které přijímá pouze verzi a akce 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 CreateMessage přetížení, které také přebírá XmlObjectSerializer parametr.

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

CreateMessage Existují přetížení, která přebírají tělo XmlReader nebo XmlDictionaryReader pro tělo 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 představují celou zprávu, a ne jen 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írnit možnost útoku dos. 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.OnWriteBodyContentsXmlDictionaryWriter, která přebírá ; tato metoda je zodpovědná za napsání těla.

Zapisovače textu lze ukládat do vyrovnávací paměti nebo ne vyrovnávací paměti (streamovat). Zapisovače těla ve vyrovnávací paměti můžou svůj obsah zapsat libovolný početkrát, zatímco streamované zapisují obsah 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č těla voláním chráněného BodyWriter konstruktoru, který přebírá isBuffered logický parametr. Zapisovače textu podporují vytvoření zapisovače těla ve vyrovnávací paměti z ne vyrovnávací paměti 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 WriteBodyContents a CreateBufferedCopy metody, které jsou v podstatě tenké obálky kolem OnWriteBodyContents a OnCreateBufferedCopy metody, v uvedeném pořadí. Tyto metody provádějí kontrolu stavu, aby se zajistilo, že se k zapisovači těla, který není uložen v vyrovnávací paměti, nemá přístup 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í jsou k dispozici pro usnadnění. První takové přetížení vezme FaultCode řetězec a důvod a vytvoří MessageFault pomocí těchto informací použití MessageFault.CreateFault . Druhé přetížení přebírá objekt podrobností a také ho předává společně CreateFault s kódem chyby 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 jeho těla. 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.

  • Celá zpráva, včetně jejího textu, lze zkopírovat do vyrovnávací paměti MessageBuffer typu. 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 Napsaných, Read a Copied. 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říkladsoap:body<> ). WriteMessage Nakonec zapíše celou zprávu, včetně obtékání 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 zapisuje určité značky elementů start 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, <soap:Envelope>například .

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

Čtení zpráv

Primárním způsobem čtení textu zprávy je volání GetReaderAtBodyContents. Vrátíte se zpátky XmlDictionaryReader , pomocí kterého si můžete přečíst text zprávy. Všimněte si, že Message přechody do stavu čtení ihned po GetReaderAtBodyContents zavolání, a ne při použití vrácené čtečky XML.

Metoda GetBody také umožňuje přístup k textu zprávy jako typ objektu. Interně tato metoda používá GetReaderAtBodyContentsa proto také přemístit stav zprávy do Read stavu (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 (označeného obecným parametrem) pomocí DataContractSerializer nakonfigurovaného s výchozím nastavením a se zakázanou kvótou 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é ukládat 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ří vyrovnávací paměť, která není větší než tato velikost. Pokud zpráva pochází z nedůvěryhodného zdroje, je důležité ji nastavit na bezpečnou hodnotu.

Vyrovnávací paměť se vrátí jako MessageBuffer instance. K datům ve vyrovnávací paměti můžete přistupovat několika způsoby. Primárním způsobem je volat CreateMessage vytváření Message instancí 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é kvótou uzlů, což omezuje počet uzlů, které je možné navštívit. 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 má prázdné znaky zpracovávat v JAZYCE XML pomocí výčtu XmlSpace s výchozím nastavením XmlSpace.None.

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

Následující příklad ukazuje proces práce s MessageBuffer: příchozí zpráva se přepošla více příjemcům a pak se protokoluje 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 lze volat k uvolnění prostředků, pokud už 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 , která získá 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ě Message , že je ve stavu Vytvoření (pokud text zprávy ještě nebyl přístup).

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é prostřednictvím Headers vlastnosti typu MessageHeaders. MessageHeaders je kolekce MessageHeaderInfo objektů a jednotlivé hlavičky lze získat přístup prostřednictvím jeho 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 posunou pro vloženou položku. Záhlaví jsou seřazená podle indexu a první dostupný index je 0. Pomocí různých CopyHeadersFrom přetížení metod můžete přidat hlavičky z jiné Message nebo MessageHeaders instance. 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 oborem názvů.

Načtěte konkrétní hlavičku FindHeader pomocí metody. Tato metoda vezme název a obor názvů hlavičky k vyhledání a vrátí jeho 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ásadnější FindHeader přetížení hledá pouze hlavičky určené pro konečný 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 záhlaví. Chcete-li deserializovat obsah záhlaví do objektu, použijte GetHeader<T>(Int32) nebo jeden z dalších přetížení. Nejzásadnější přetížení deserializovat hlavičky pomocí DataContractSerializer nakonfigurovaného výchozího způsobu. Chcete-li použít jiný serializátor nebo jinou konfiguraci DataContractSerializer, použijte jedno z přetížení, které přebírají 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 v drátě, ale spíše poskytují různé rady zpracování zpráv pro různé kanály v zásobníku kanálu WCF nebo na CopyTo(MessageHeaderInfo[], Int32) rozhraní služby. Příklad najdete v tématu Přehled architektury přenosu dat.

Dědění z třídy zprávy

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 OnWriteBodyContentsvolání , OnGetReaderAtBodyContentsa OnCreateBufferedCopy metody , 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ětšině případů mají výchozí OnGetReaderAtBodyContents() implementace, OnCreateBufferedCopy které fungují. Výchozí volání OnWriteBodyContentsimplementace , uložení výsledků do vyrovnávací paměti a práce s výslednou vyrovnávací pamětí. 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í. Můžete chtít přepsat OnGetReaderAtBodyContents() vrácení vlastní XmlDictionaryReader odvozené třídy, která obsluhuje náhodná čísla. Potom můžete přepsat OnWriteBodyContents použití čtečky, kterou OnGetReaderAtBodyContents() metoda 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 , aby se vrátila vlastní MessageBuffer odvozená třída.

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

Všimněte si, že pokud vytvoříte kopii zprávy, použije kopie záhlaví zprávy z originálu.

Ostatní členové, kteří je možné přepsat

Můžete přepsat OnWriteStartEnvelope, OnWriteStartHeadersa OnWriteStartBody metody určit, jak se obálka SOAP, hlavičky SOAP a základní značky SOAP elementu zapisují značky. 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ání OnWriteStartEnvelope a OnWriteStartBody před voláním OnWriteBodyContents a uložení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í osvědčeným postupem. 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 reprezentovat jako tři tečky (...). 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čet, ale Message základní typ zaručuje, že je volána pouze v případě, že zpráva je ve stavu Vytvoření. 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 objekt Message musí provést jakékoli zvláštní vyčištění, pokud už text zprávy není vyžadován, můžete přepsat OnClose. Výchozí implementace nic nedělá.

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