Sdílet prostřednictvím


Strukturální přehled přenosu dat

Windows Communication Foundation (WCF) si můžete představit jako infrastrukturu zasílání zpráv. Může přijímat zprávy, zpracovávat je a odesílat do uživatelského kódu pro další akci, nebo může vytvářet zprávy z dat zadaných uživatelským kódem a doručovat je do cíle. Toto téma, které je určené pro pokročilé vývojáře, popisuje architekturu pro zpracování zpráv a obsažených dat. Jednodušší přehled o tom, jak odesílat a přijímat data, najdete v tématu Určení přenosu dat v kontraktech služeb.

Poznámka:

Toto téma popisuje podrobnosti implementace WCF, které nejsou viditelné prozkoumáním objektového modelu WCF. V souvislosti s zdokumentovanými podrobnostmi o implementaci jsou v pořádku dvě slova opatrnosti. Zaprvé jsou popisy zjednodušené; skutečná implementace může být složitější kvůli optimalizaci nebo jiným důvodům. Za druhé byste se nikdy neměli spoléhat na konkrétní podrobnosti implementace, ani na zdokumentované podrobnosti, protože se můžou změnit bez upozornění z verze na verzi nebo dokonce v servisní verzi.

Základní architektura

Jádrem schopností zpracování zpráv WCF je Message třída, která je podrobně popsána v použití třídy message. Komponenty WCF za běhu lze rozdělit do dvou hlavních částí: zásobník kanálu a rozhraní služby, přičemž Message třída je spojovacím bodem.

Zásobník kanálu zodpovídá za převod mezi platnou Message instancí a určitou akcí, která odpovídá odesílání nebo přijímání dat zpráv. Na straně odesílání zásobník kanálu přijme platnou Message instanci a po nějakém zpracování provede nějakou akci, která logicky odpovídá odeslání zprávy. Akce může posílat pakety TCP nebo HTTP, zapisovat zprávu do fronty ve službě Řízení front zpráv, zapisovat zprávu do databáze, ukládat ji do sdílené složky nebo jakoukoli jinou akci v závislosti na implementaci. Nejběžnější akcí je odeslání zprávy přes síťový protokol. Na straně příjmu dojde k opaku – akce se zjistí (což může být pakety TCP nebo HTTP přicházející nebo jakékoli jiné akce) a po zpracování zásobník kanálu tuto akci převede na platnou Message instanci.

WCF můžete použít přímo pomocí Message třídy a zásobníku kanálů. Je to ale obtížné a časově náročné. Objekt navíc Message neposkytuje žádnou podporu metadat, takže nelze generovat klienty WCF silného typu, pokud používáte WCF tímto způsobem.

WCF proto obsahuje rozhraní služby, které poskytuje snadno použitelný programovací model, který můžete použít k vytváření a přijímání Message objektů. Architektura služby mapuje služby na typy rozhraní .NET Framework prostřednictvím pojmů kontraktů služeb a odesílá zprávy do uživatelských operací, které jsou jednoduše metody rozhraní .NET Framework označené atributem OperationContractAttribute (další podrobnosti najdete v tématu Návrh kontraktů služeb). Tyto metody mohou mít parametry a návratové hodnoty. Na straně služby architektura služby převede příchozí Message instance na parametry a převede vrácené hodnoty na odchozí Message instance. Na straně klienta to dělá opačně. Představte si FindAirfare například následující operaci.

[ServiceContract]
public interface IAirfareFinderService
{
    [OperationContract]
    int FindAirfare(string FromCity, string ToCity, out bool IsDirectFlight);
}
<ServiceContract()> _
Public Interface IAirfareFinderService

    <OperationContract()> _
    Function FindAirfare(ByVal FromCity As String, _
    ByVal ToCity As String, ByRef IsDirectFlight As Boolean) As Integer

End Interface

Předpokládejme, že FindAirfare je v klientovi volána. Architektura služby na klientovi převede FromCity parametry ToCity na odchozí Message instanci a předá ji do zásobníku kanálu, který se má odeslat.

Když instance dorazí ze zásobníku kanálu, na straně Message služby extrahuje příslušná data ze zprávy, aby se naplnily FromCity parametry a ToCity potom volaly metodu na straně FindAirfare služby. Když metoda vrátí, rozhraní služby vezme vrácenou celočíselnou hodnotu a IsDirectFlight výstupní parametr a vytvoří instanci objektu Message , která obsahuje tyto informace. Pak předá Message instanci do zásobníku kanálu, který se má odeslat zpět klientovi.

Na straně klienta se z zásobníku kanálu objeví instance, Message která obsahuje zprávu odpovědi. Architektura služby extrahuje návratovou hodnotu a IsDirectFlight hodnotu a vrátí je volajícímu klienta.

Message – třída

Třída Message je určena jako abstraktní reprezentace zprávy, ale její návrh je silně svázaný se zprávou SOAP. A Message obsahuje tři hlavní informace: text zprávy, záhlaví zprávy a vlastnosti zprávy.

Text zprávy

Text zprávy představuje skutečnou datovou část zprávy. Text zprávy je vždy reprezentován jako informační sada XML. To neznamená, že všechny zprávy vytvořené nebo přijaté ve WCF musí být ve formátu XML. Záleží na zásobníku kanálu, abyste se rozhodli, jak interpretovat text zprávy. Může ho generovat jako XML, převést ho do jiného formátu nebo dokonce zcela vynechat. Samozřejmě, že většina vazeb WCF dodává, text zprávy je reprezentován jako xml obsah v části textu obálky SOAP.

Je důležité si uvědomit, že Message třída nemusí nutně obsahovat vyrovnávací paměť s daty XML představujícími tělo. Logicky Message obsahuje informační sadu XML, ale tato informační sada může být dynamicky vytvořena a nemusí nikdy fyzicky existovat v paměti.

Vložení dat do textu zprávy

Neexistuje žádný jednotný mechanismus pro vložení dat do textu zprávy. Třída Message má abstraktní metodu, OnWriteBodyContents(XmlDictionaryWriter)která přebírá XmlDictionaryWriter. Každá podtřída Message třídy zodpovídá za přepsání této metody a zapisování vlastního obsahu. Tělo zprávy logicky obsahuje xml infoset, který OnWriteBodyContent vytvoří. Představte si například následující Message podtřídu.

public class AirfareRequestMessage : Message
{
    public string fromCity = "Tokyo";
    public string toCity = "London";
    //code omitted…
    protected override void OnWriteBodyContents(XmlDictionaryWriter w)
    {
        w.WriteStartElement("airfareRequest");
        w.WriteElementString("from", fromCity);
        w.WriteElementString("to", toCity);
        w.WriteEndElement();
    }

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

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

    public override bool IsEmpty
    {
        get
        {
            return base.IsEmpty;
        }
    }

    public override bool IsFault
    {
        get
        {
            return base.IsFault;
        }
    }
}
Public Class AirfareRequestMessage
    Inherits Message

    Public fromCity As String = "Tokyo"
    Public toCity As String = "London"
    ' Code omitted…
    Protected Overrides Sub OnWriteBodyContents(ByVal w As XmlDictionaryWriter)
        w.WriteStartElement("airfareRequest")
        w.WriteElementString("from", fromCity)
        w.WriteElementString("to", toCity)
        w.WriteEndElement()
    End Sub

    Public Overrides ReadOnly Property Version() As MessageVersion
        Get
            Throw New NotImplementedException("The method 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 Headers() As MessageHeaders
        Get
            Throw New Exception("The method or operation is not implemented.")
        End Get
    End Property


    Public Overrides ReadOnly Property IsEmpty() As Boolean
        Get
            Return MyBase.IsEmpty
        End Get
    End Property

    Public Overrides ReadOnly Property IsFault() As Boolean
        Get
            Return MyBase.IsFault
        End Get
    End Property
End Class

AirfareRequestMessage Fyzicky instance obsahuje pouze dva řetězce ("fromCity" a "toCity"). Logicky však zpráva obsahuje následující informační sadu XML:

<airfareRequest>  
    <from>Tokyo</from>  
    <to>London</to>  
</airfareRequest>  

Samozřejmě byste normálně nevytvoří zprávy tímto způsobem, protože můžete použít rozhraní služby k vytvoření zprávy jako předchozí z parametrů kontraktu operace. Kromě toho třída má statické metody, Message které můžete použít k vytváření zpráv s běžnými typy obsahu: prázdná zpráva, zpráva obsahující objekt serializovaný do XML s DataContractSerializer, zpráva obsahující chybu SOAP, zprávu obsahující XML reprezentovaný objektem XmlReaderCreateMessage atd.

Získání dat z textu zprávy

Data uložená v textu zprávy můžete extrahovat dvěma hlavními způsoby:

  • Celý text zprávy můžete získat najednou voláním WriteBodyContents(XmlDictionaryWriter) metody a předáním zapisovače XML. Celé tělo zprávy je zapsáno do tohoto spisovatele. Získání celého textu zprávy najednou se označuje také jako zápis zprávy. Psaní se provádí především zásobníkem kanálu při odesílání zpráv – některá část zásobníku kanálu obvykle získá přístup k celému textu zprávy, zakóduje ho a odešle.

  • Dalším způsobem, jak získat informace z textu zprávy, je volání GetReaderAtBodyContents() a získání čtečky XML. Text zprávy se pak dá podle potřeby přistupovat postupně voláním metod čtenáře. Získání základní části zprávy se také označuje jako čtení zprávy. Čtení zprávy je primárně používáno rozhraním služby při přijímání zpráv. Pokud se například DataContractSerializer používá, rozhraní služby získá čtečku XML nad tělem a předá ji modulu deserializace, který pak začne číst element zprávy po elementu a sestavení odpovídajícího objektového grafu.

Text zprávy lze načíst pouze jednou. To umožňuje pracovat s datovými proudy jen pro předávání. Můžete například napsat OnWriteBodyContents(XmlDictionaryWriter) přepsání, které čte z a FileStream vrátí výsledky jako informační sadu XML. Nikdy nebudete muset "převinout zpět" na začátek souboru.

Tyto WriteBodyContents metody GetReaderAtBodyContents jednoduše zkontrolují, že tělo zprávy nebylo nikdy načteno, a pak zavolejte OnWriteBodyContents nebo OnGetReaderAtBodyContents, v uvedeném pořadí.

Použití zpráv ve WCF

Většinu zpráv je možné klasifikovat jako odchozí (ty, které jsou vytvořeny rozhraním služby, které se mají odesílat zásobníkem kanálu) nebo jako příchozí (ty, které přicházejí ze zásobníku kanálu a jsou interpretovány rozhraním služby). Zásobník kanálů navíc může fungovat buď v režimu vyrovnávací paměti, nebo v režimu streamování. Architektura služby může také vystavit streamovaný nebo nestreamovaný programovací model. To vede k případům uvedeným v následující tabulce spolu se zjednodušenými podrobnostmi o jejich implementaci.

Typ zprávy Textová data ve zprávě Implementace Write (OnWriteBodyContents) Implementace Read (OnGetReaderAtBodyContents)
Odchozí, vytvořené z nestreamového programovacího modelu Data potřebná k zápisu zprávy (například objekt a DataContractSerializer instance potřebné k jeho serializaci)* Vlastní logika pro zápis zprávy na základě uložených dat (například volání WriteObjectDataContractSerializer , pokud se používá serializátor)* Volání OnWriteBodyContents, uložení výsledků do vyrovnávací paměti, vrácení čtečky XML do vyrovnávací paměti
Odchozí, vytvořené ze streamovaného programovacího modelu Data Stream , která se mají zapsat* Zapisování dat z uloženého datového proudu pomocí IStreamProvider mechanismu* Volání OnWriteBodyContents, uložení výsledků do vyrovnávací paměti, vrácení čtečky XML do vyrovnávací paměti
Příchozí ze zásobníku streamovaných kanálů Objekt Stream , který představuje data přicházející přes síť s jeho XmlReader prostřednictvím Zapsat obsah z uloženého XmlReader pomocí WriteNode Vrátí uloženou hodnotu. XmlReader
Příchozí ze zásobníku nestreamových kanálů Vyrovnávací paměť, která obsahuje základní data s nad XmlReader ním Zapíše obsah z uloženého XmlReader pomocí příkazu WriteNode Vrátí uloženou jazyk.

* Tyto položky nejsou implementovány přímo v Message podtřídách, ale v podtřídách BodyWriter třídy. Další informace o této BodyWritertřídě naleznete v tématu Použití třídy zprávy.

Záhlaví zpráv

Zpráva může obsahovat záhlaví. Hlavička se logicky skládá z informační sady XML, která je přidružena k názvu, oboru názvů a několika dalším vlastnostem. K záhlavím zpráv se přistupuje pomocí Headers vlastnosti on Message. Každé záhlaví je reprezentováno MessageHeader třídou. Záhlaví zpráv se obvykle mapují na hlavičky zpráv SOAP při použití zásobníku kanálu nakonfigurovaného pro práci se zprávami SOAP.

Vložení informací do záhlaví zprávy a extrakce informací z ní se podobá použití textu zprávy. Proces je poněkud zjednodušený, protože streamování se nepodporuje. K obsahu stejné hlavičky je možné přistupovat více než jednou a k záhlavím je možné přistupovat v libovolném pořadí a vynucovat tak, aby se hlavičky vždy ukládaly do vyrovnávací paměti. Neexistuje žádný mechanismus pro obecné účely pro získání čtečky XML nad hlavičkou, ale existuje MessageHeader interní podtřída WCF, která představuje čitelné záhlaví s takovou schopností. Tento typ MessageHeader je vytvořen zásobníkem kanálu, když přijde zpráva s vlastními hlavičkami aplikace. To umožňuje rozhraní služby použít deserializační modul, například DataContractSerializer, k interpretaci těchto hlaviček.

Další informace naleznete v tématu Použití třídy zprávy.

Vlastnosti zprávy

Zpráva může obsahovat vlastnosti. Vlastnost je jakýkoli objekt rozhraní .NET Framework, který je přidružen k názvu řetězce. Vlastnosti jsou přístupné prostřednictvím Properties vlastnosti on Message.

Na rozdíl od textu zprávy a záhlaví zprávy (která se obvykle mapují na hlavičky SOAP a SOAP), vlastnosti zprávy se spolu se zprávami obvykle neodesílají ani nepřijímají. Vlastnosti zpráv existují primárně jako komunikační mechanismus pro předávání dat o zprávě mezi různými kanály v zásobníku kanálů a mezi zásobníkem kanálů a modelem služby.

Například přenosový kanál HTTP zahrnutý jako součást WCF dokáže vytvářet různé stavové kódy HTTP, například 404 (Nenalezena) a 500 (vnitřní chyba serveru), když odesílá odpovědi klientům. Před odesláním zprávy odpovědi zkontroluje, zda PropertiesMessage obsahují vlastnost s názvem "httpResponse", která obsahuje objekt typu HttpResponseMessageProperty. Pokud se taková vlastnost najde, podívá se na StatusCode vlastnost a použije tento stavový kód. Pokud se nenajde, použije se výchozí kód 200 (OK).

Další informace naleznete v tématu Použití třídy zprávy.

Zpráva jako Kdo le

Zatím jsme probrali metody pro přístup k různým částem zprávy izolovaně. Message Třída však také poskytuje metody pro práci s celou zprávou jako celku. Například WriteMessage metoda zapisuje celou zprávu do zapisovače XML.

Aby bylo možné, musí být mapování definováno mezi celou Message instancí a xml infoset. Takové mapování ve skutečnosti existuje: WCF k definování tohoto mapování používá standard SOAP. Message Když je instance zapsána jako XML Infoset, výsledný infoset je platná obálka SOAP, která obsahuje zprávu. WriteMessage Obvykle by tedy prováděl následující kroky:

  1. Napište počáteční značku elementu obálky SOAP.

  2. Napište počáteční značku elementu záhlaví SOAP, zapište všechny záhlaví a zavřete prvek záhlaví.

  3. Napište počáteční značku základního prvku SOAP.

  4. Volání WriteBodyContents nebo ekvivalentní metoda pro zápis textu.

  5. Zavřete tělo a prvky obálky.

Předchozí kroky jsou úzce svázané se standardem SOAP. To je komplikované skutečností, že existuje více verzí protokolu SOAP, například není možné správně zapsat prvek obálky SOAP bez znalosti používané verze PROTOKOLU SOAP. V některých případech může být také žádoucí úplně vypnout toto komplexní mapování specifické pro SOAP.

Pro tyto účely je vlastnost poskytována Version na Message. Dá se nastavit na verzi PROTOKOLU SOAP, která se má použít při zápisu zprávy, nebo může být nastavená tak, aby None se zabránilo mapování specifické pro protokol SOAP. Pokud je vlastnost nastavena Version na None, metody, které pracují s celou zprávou fungují, jako by se zpráva skládala pouze z textu, například by WriteMessage jednoduše volala WriteBodyContents místo provádění více kroků uvedených výše. Očekává se, Version že u příchozích zpráv se automaticky rozpozná a nastaví správně.

Zásobník kanálů

Kanály

Jak je uvedeno dříve, zásobník kanálu zodpovídá za převod odchozích Message instancí na nějakou akci (například odesílání paketů přes síť) nebo převod určité akce (například příjem síťových paketů) na příchozí Message instance.

Zásobník kanálů se skládá z jednoho nebo více kanálů seřazených v posloupnosti. Odchozí Message instance se předává do prvního kanálu v zásobníku (označovaný také jako nejvyšší kanál), který ho předává do dalšího kanálu v zásobníku a tak dále. Zpráva se ukončí v posledním kanálu, který se nazývá přenosový kanál. Příchozí zprávy pocházejí z přenosového kanálu a předávají se z kanálu do zásobníku. Z nejvyššího kanálu se zpráva obvykle předává do architektury služby. I když se jedná o obvyklý vzor pro zprávy aplikace, některé kanály můžou fungovat trochu jinak, například můžou posílat vlastní zprávy infrastruktury, aniž by byly předány zprávy z výše uvedeného kanálu.

Kanály můžou na zprávě pracovat různými způsoby, jak prochází zásobníkem. Nejběžnější operací je přidání záhlaví do odchozí zprávy a čtení hlaviček příchozí zprávy. Kanál může například vypočítat digitální podpis zprávy a přidat ji jako záhlaví. Kanál může také zkontrolovat toto záhlaví digitálního podpisu u příchozích zpráv a blokovat zprávy, které nemají platný podpis, aby se jejich cesta do zásobníku kanálu. Kanály také často nastavují nebo kontrolují vlastnosti zpráv. Text zprávy se obvykle nezmění, i když je to povolené, například kanál zabezpečení WCF může šifrovat text zprávy.

Přenosové kanály a kodéry zpráv

Nejspodnější kanál v zásobníku je zodpovědný za skutečně transformaci odchozího Messagekanálu , jak je upraveno jinými kanály, na nějakou akci. Na straně příjmu se jedná o kanál, který převede určitou akci na Message proces jiného kanálu.

Jak jsme uvedli dříve, akce se můžou lišit: odesílání nebo příjem síťových paketů přes různé protokoly, čtení nebo zápis zprávy do databáze nebo zařazení zprávy do fronty nebo zrušení fronty zpráv ve frontě služby Řízení front zpráv, ale několik příkladů. Všechny tyto akce mají jednu věc společného: vyžadují transformaci mezi instancí WCFMessage a skutečnou skupinou bajtů, které je možné odesílat, přijímat, číst, zapisovat, zapsat, zařadit do fronty nebo odložit. Proces převodu na Message skupinu bajtů se nazývá kódování a reverzní proces vytvoření Message ze skupiny bajtů se nazývá dekódování.

Většina přenosových kanálů používá komponenty označované jako kodéry zpráv k provádění kódování a dekódování. Kodér zpráv je podtřídou MessageEncoder třídy. MessageEncoder zahrnuje různá ReadMessage přetížení a WriteMessage přetížení metod pro převod mezi Message bajty a skupinami bajtů.

Na straně odesílání přenosový kanál vyrovnávací paměti předá Message objekt, který přijal z kanálu nad ním .WriteMessage Získá zpět pole bajtů, které pak použije k provedení své akce (například zabalení těchto bajtů jako platných paketů TCP a jejich odeslání do správného cíle). Nejprve vytvoří Stream streamovací přenosový kanál (například přes odchozí připojení TCP) a pak předá i StreamMessage ten, který je potřeba odeslat do příslušného WriteMessage přetížení, který zprávu zapíše.

Na straně příjmu extrahuje transportní kanál do vyrovnávací paměti příchozí bajty (například z příchozích paketů TCP) do pole a volání ReadMessage pro získání objektu Message , který může předat dále zásobník kanálu. Přenosový kanál streamování vytvoří Stream objekt (například síťový stream přes příchozí připojení TCP) a předá ho, aby ReadMessage se objekt získal zpět Message .

Oddělení mezi přenosovými kanály a kodérem zpráv není povinné; Je možné napsat přenosový kanál, který nepoužívá kodér zpráv. Výhodou tohoto rozdělení je však snadné složení. Pokud přenosový kanál používá pouze základ MessageEncoder, může pracovat s libovolným kodérem WCF nebo kódem zpráv třetích stran. Stejně tak stejný kodér lze normálně použít v libovolném přenosovém kanálu.

Operace kodéru zpráv

Pokud chcete popsat typickou operaci kodéru, je vhodné vzít v úvahu následující čtyři případy.

Operace Komentář
Kódování, ukládání do vyrovnávací paměti V režimu vyrovnávací paměti kodér obvykle vytvoří vyrovnávací paměť proměnné velikosti a pak vytvoří zapisovač XML. Potom volá WriteMessage(XmlWriter) zakódovanou zprávu, která zapisuje hlavičky a pak tělo pomocí WriteBodyContents(XmlDictionaryWriter), jak je vysvětleno v předchozí části o Message tomto tématu. Obsah vyrovnávací paměti (reprezentované jako pole bajtů) se pak vrátí pro přenosový kanál, který se má použít.
Kódování, streamování V režimu streamování se operace podobá výše uvedenému, ale jednoduššímu. Není potřeba mít vyrovnávací paměť. Zapisovač XML je obvykle vytvořen přes datový proud a WriteMessage(XmlWriter) je volána Message k jeho zápisu do tohoto zapisovače.
Dekódování, ukládání do vyrovnávací paměti Při dekódování v režimu vyrovnávací paměti se obvykle vytvoří speciální Message podtřída obsahující uložená data ve vyrovnávací paměti. Záhlaví zprávy se čtou a vytvoří se čtečka XML umístěná v textu zprávy. To je čtenář, který bude vrácen s GetReaderAtBodyContents().
Dekódování, streamované Při dekódování v streamovaném režimu se obvykle vytvoří speciální podtřída zprávy. Stream je dostatečně pokročilý, aby přečetl všechna záhlaví a umístil ho do textu zprávy. Čtečka XML se pak vytvoří přes stream. To je čtenář, který bude vrácen s GetReaderAtBodyContents().

Kodéry můžou také provádět další funkce. Kodéry můžou například s fondem čteček XML a zapisovačů. Vytvoření nové čtečky XML nebo zapisovače je nákladné pokaždé, když je potřeba. Kodéry proto obvykle udržují fond čtenářů a fond zapisovačů konfigurovatelné velikosti. V popisech operace kodéru popsané dříve, vždy, když se použije fráze "vytvoření čtečky NEBO zapisovače XML", obvykle to znamená "vzít jeden z fondu nebo vytvořit, pokud není k dispozici". Kodér (a Message podtřídy, které vytváří při dekódování), obsahuje logiku pro vrácení čtenářů a zapisovačů do fondů, jakmile už nejsou potřeba (například při Message zavření).

WCF poskytuje tři kodéry zpráv, i když je možné vytvořit další vlastní typy. Zadané typy jsou Text, Binary a Message Transmission Optimization Mechanism (MTOM). Tyto informace jsou podrobně popsány při výběru kodéru zpráv.

IStreamProvider – rozhraní

Při zápisu odchozí zprávy, která obsahuje streamované tělo do zapisovače XML, Message používá posloupnost volání podobná následující v jeho OnWriteBodyContents(XmlDictionaryWriter) implementaci:

  • Zapište všechny potřebné informace před streamem (například počáteční značku XML).

  • Napište stream.

  • Zapište všechny informace za streamem (například zavírací značku XML).

To funguje dobře s kódováními, které jsou podobné textovému kódování XML. Některá kódování však neumisťují informace XML Infoset (například značky pro počáteční a koncové elementy XML) spolu s daty obsaženými v elementech. Například v kódování MTOM je zpráva rozdělena do více částí. Jedna část obsahuje informační sadu XML, která může obsahovat odkazy na jiné části pro skutečný obsah elementu. Informační sada XML je obvykle malá ve srovnání s streamovaným obsahem, takže dává smysl ukládat informace do vyrovnávací paměti, zapisovat je a pak psát obsah streamovaným způsobem. To znamená, že po napsání značky uzavíracího prvku by stream ještě neměl být zapsán.

Pro tento účel IStreamProvider se používá rozhraní. Rozhraní má metodu GetStream() , která vrací datový proud, který má být zapsán. Správný způsob, jak napsat text streamované zprávy OnWriteBodyContents(XmlDictionaryWriter) , je následující:

  1. Zapište všechny potřebné informace před streamem (například počáteční značku XML).

  2. WriteValue Zavolejte přetížení na XmlDictionaryWriter tom, který přebírá IStreamProvider, s IStreamProvider implementací, která vrací datový proud, který má být zapsán.

  3. Zapište všechny informace za streamem (například zavírací značku XML).

Při tomto přístupu má zapisovač XML možnost, kdy volat GetStream() a zapisovat streamovaná data. Textové a binární zapisovače XML ho například okamžitě volají a zapisují streamovaný obsah mezi počátečními a koncovými značkami. Zapisovač MTOM se může rozhodnout zavolat GetStream() později, až bude připraven napsat příslušnou část zprávy.

Reprezentace dat v rozhraní service Framework

Jak je uvedeno v části Základní architektura tohoto tématu, architektura služby je součástí WCF, která mimo jiné zodpovídá za převod mezi uživatelsky přívětivým programovacím modelem pro data zpráv a skutečné Message instance. Za normálních okolností je výměna zpráv reprezentována v rozhraní služby jako metoda rozhraní .NET Framework označená atributem OperationContractAttribute . Metoda může převzít některé parametry a může vrátit návratovou hodnotu nebo out parametry (nebo obojí). Na straně služby vstupní parametry představují příchozí zprávu a návratové a výstupní parametry představují odchozí zprávu. Na straně klienta je opačná hodnota true. Programovací model popisující zprávy pomocí parametrů a návratová hodnota je podrobně popsána v části Určení přenosu dat v kontraktech služeb. Tato část ale poskytne stručný přehled.

Programovací modely

Architektura služby WCF podporuje pět různých programovacích modelů pro popis zpráv:

1. Prázdná zpráva

To je nejjednodušší případ. K popisu prázdné příchozí zprávy nepoužívejte žádné vstupní parametry.

[OperationContract]
int GetCurrentTemperature();
<OperationContract()> Function GetCurrentTemperature() As Integer

Pokud chcete popsat prázdnou odchozí zprávu, použijte návratovou hodnotu void a nepoužívejte žádné výstupní parametry:

[OperationContract]
void SetDesiredTemperature(int t);
<OperationContract()> Sub SetDesiredTemperature(ByVal t As Integer)

Všimněte si, že se liší od jednosměrného kontraktu operace:

[OperationContract(IsOneWay = true)]
void SetLightbulb(bool isOn);
<OperationContract(IsOneWay:=True)> Sub SetLightbulb(ByVal isOn As Boolean)

V tomto příkladu SetDesiredTemperature je popsán obousměrný vzor výměny zpráv. Z operace se vrátí zpráva, ale je prázdná. Z operace je možné vrátit chybu. V příkladu Nastavit žárovku je vzor výměny zpráv jednosměrný, takže neexistuje žádná odchozí zpráva, kterou byste chtěli popsat. Služba nemůže v tomto případě klientovi sdělit žádný stav.

2. Přímé použití třídy zpráv

Třídu (nebo jednu z jejích podtříd) je možné použít Message přímo v kontraktu operace. V tomto případě architektura služby právě předává Message z operace do zásobníku kanálu a naopak bez dalšího zpracování.

Existují dva hlavní případy použití pro přímé použití Message . Tuto možnost můžete použít pro pokročilé scénáře, když žádný z ostatních programovacích modelů neposkytuje dostatečnou flexibilitu k popisu zprávy. Můžete například chtít použít soubory na disku k popisu zprávy, přičemž vlastnosti souboru se stávají záhlavími zpráv a obsahem souboru se stává textem zprávy. Pak můžete vytvořit něco podobného jako v následujícím příkladu.

public class FileMessage : Message
// Code not shown.
Public Class FileMessage
    Inherits Message
    ' Code not shown.

Druhým běžným použitím Message kontraktu operace je, že služba nezajímá konkrétní obsah zprávy a funguje na zprávě jako v černém rámečku. Můžete mít například službu, která přeposílala zprávy více dalším příjemcům. Smlouvu lze napsat následujícím způsobem.

[OperationContract]
public FileMessage GetFile()
{
    //code omitted…
    FileMessage fm = new FileMessage("myFile.xml");
    return fm;
}
<OperationContract()> Public Function GetFile() As FileMessage
    'code omitted…
    Dim fm As New FileMessage("myFile.xml")
    Return fm
End Function

Řádek Action="*" efektivně vypne odesílání zpráv a zajistí, aby všechny zprávy odeslané do kontraktu IForwardingServiceForwardMessage udělaly cestu k operaci. (Dispečer obvykle zkontroluje hlavičku akce zprávy a určí, pro kterou operaci je určená. Action="*" znamená "všechny možné hodnoty záhlaví akce".) Kombinace action="*" a použití zprávy jako parametru se označuje jako "univerzální kontrakt", protože dokáže přijímat všechny možné zprávy. Pokud chcete být schopni odesílat všechny možné zprávy, použijte jako návratovou hodnotu Message a nastavte ReplyAction na *. Tím zabráníte, aby architektura služby přidala vlastní hlavičku akce, což vám umožní řídit tuto hlavičku pomocí vráceného objektu Message .

3. Smlouvy o zprávách

WCF poskytuje deklarativní programovací model pro popis zpráv označovaný jako kontrakty zpráv. Tento model je podrobně popsán v části Používání kontraktů zpráv. V podstatě je celá zpráva reprezentována jedním typem rozhraní .NET Framework, který používá atributy jako MessageBodyMemberAttribute a MessageHeaderAttribute popisuje, které části třídy kontraktu zpráv by se měly mapovat na kterou část zprávy.

Kontrakty zpráv poskytují velkou kontrolu nad výslednými Message instancemi (i když samozřejmě není tolik ovládacích prvků, jako je použití Message třídy přímo). Například těla zpráv se často skládají z více informací, z nichž každý představuje vlastní prvek XML. Tyto prvky mohou nastat buď přímo v těle (holý režim), nebo mohou být zabaleny do zahrnující xml elementu. Použití programovacího modelu kontraktu zpráv umožňuje provést úplné a zabalené rozhodnutí a řídit název názvu obálky a oboru názvů.

Následující příklad kódu kontraktu zprávy ukazuje tyto funkce.

[MessageContract(IsWrapped = true, WrapperName = "Order")]
public class SubmitOrderMessage
{
    [MessageHeader]
    public string customerID;
    [MessageBodyMember]
    public string item;
    [MessageBodyMember]
    public int quantity;
}
<MessageContract(IsWrapped:=True, WrapperName:="Order")> _
Public Class SubmitOrderMessage
    <MessageHeader()> Public customerID As String
    <MessageBodyMember()> Public item As String
    <MessageBodyMember()> Public quantity As Integer
End Class

Položky označené k serializaci (s MessageBodyMemberAttribute, MessageHeaderAttributenebo jinými souvisejícími atributy) musí být serializovatelné pro účast ve smlouvě zprávy. Další informace naleznete v části Serializace dále v tomto tématu.

4. Parametry

Vývojář, který chce často popsat operaci, která funguje na více částech dat, nepotřebuje stupeň kontroly, kterou kontrakty zpráv poskytují. Například při vytváření nových služeb se obvykle nechce rozhodnout o holé versus zabalené rozhodnutí a rozhodnout o názvu elementu obálky. Tato rozhodnutí často vyžadují hluboké znalosti webových služeb a protokolu SOAP.

Architektura služby WCF může automaticky vybrat nejlepší a nejoperabilní reprezentaci PROTOKOLU SOAP pro odesílání nebo přijímání více souvisejících informací bez vynucení těchto voleb pro uživatele. Toho dosáhnete jednoduchým popisem těchto informací jako parametrů nebo návratovými hodnotami kontraktu operace. Představte si například následující kontrakt operace.

[OperationContract]
void SubmitOrder(string customerID, string item, int quantity);
<OperationContract()> _
Sub SubmitOrder( _
    ByVal customerID As String, _
    ByVal item As String, _
    ByVal quantity As Integer)

Architektura služby se automaticky rozhodne vložit všechny tři části informací (customerID, itema quantity) do textu zprávy a zabalit je do elementu obálky s názvem SubmitOrderRequest.

Popisinformacíchm informacím je doporučeným přístupem, pokud neexistují zvláštní důvody přechodu na složitější kontrakt nebo Messageprogramovací modely založené na zprávě.

5. Stream

Použití Stream nebo jedna z jejích podtříd v kontraktu operace nebo jako základní část textu zprávy ve smlouvě zprávy lze považovat za samostatný programovací model od výše popsaných. Tímto Stream způsobem je jediným způsobem, jak zaručit, že vaše smlouva bude použitelná streamovaným způsobem, a to ve zkratce psaní vlastní podtřídy kompatibilní Message se streamováním. Další informace najdete v tématu Velké objemy dat a streamování.

Pokud Stream se tímto způsobem používá podtřídy nebo jedna z jejích podtříd, serializátor se nevyvolá. U odchozích zpráv se vytvoří speciální podtřída streamování Message a datový proud se zapíše, jak je popsáno v části rozhraní IStreamProvider . Pro příchozí zprávy vytvoří Stream architektura služby podtřídu příchozí zprávy a poskytne ji operaci.

Omezení programovacího modelu

Programovací modely popsané výše nelze libovolně kombinovat. Pokud například operace přijme typ kontraktu zprávy, musí být kontrakt zprávy jeho jediným vstupním parametrem. Kromě toho musí operace vrátit prázdnou zprávu (návratový typ void) nebo jiný kontrakt zprávy. Tato omezení programovacího modelu jsou popsána v tématech pro každý konkrétní programovací model: Použití kontraktů zpráv, použití třídy zpráv a velkých dat a streamování.

Formátování zpráv

Programovací modely popsané výše jsou podporovány připojením komponent, které se nazývají formátování zpráv do architektury služby. Formátování zpráv jsou typy, které implementují IClientMessageFormatter rozhraní IDispatchMessageFormatter nebo obojí pro použití v klientech WCF klientů a službách.

Formátovací moduly zpráv jsou obvykle zapojeny podle chování. Například DataContractSerializerOperationBehavior modul plugs in the data contract message formatter. To se provádí na straně služby nastavením Formatter správného formátovače v ApplyDispatchBehavior(OperationDescription, DispatchOperation) metodě nebo na straně klienta nastavením Formatter na správný formátovač v ApplyClientBehavior(OperationDescription, ClientOperation) metodě.

Následující tabulky uvádí metody, které může implementovat formátovač zpráv.

Rozhraní metoda Akce
IDispatchMessageFormatter DeserializeRequest(Message, Object[]) Převede příchozí Message parametry na parametry operace.
IDispatchMessageFormatter SerializeReply(MessageVersion, Object[], Object) Vytvoří odchozí Message parametry návratové hodnoty nebo výstupu operace.
IClientMessageFormatter SerializeRequest(MessageVersion, Object[]) Vytvoří odchozí Message z parametrů operace.
IClientMessageFormatter DeserializeReply(Message, Object[]) Převede příchozí Message parametry na návratovou hodnotu nebo out.

Serializace

Při každém použití kontraktů zpráv nebo parametrů k popisu obsahu zprávy je nutné použít serializaci k převodu mezi typy rozhraní .NET Framework a reprezentací XML Infoset. Serializace se používá na jiných místech WCF, například má obecnou GetBody metodu, Message kterou můžete použít ke čtení celého textu zprávy deserializované do objektu.

WCF podporuje dvě technologie serializace "out of the box" pro serializaci a deserializace parametrů a zpráv části: a DataContractSerializerXmlSerializer. Kromě toho můžete psát vlastní serializátory. Jiné části WCF (například obecná GetBody metoda nebo serializace chyb SOAP) však mohou být omezeny na použití pouze XmlObjectSerializer podtřídy (DataContractSerializer a NetDataContractSerializer, ale ne XmlSerializer), nebo mohou být dokonce pevně zakódovány pouze DataContractSerializer.

Jedná se XmlSerializer o serializační modul používaný ve webových službách ASP.NET. Jedná se DataContractSerializer o nový serializační modul, který rozumí novému programovacímu modelu kontraktu dat. DataContractSerializer je výchozí volba a možnost použití XmlSerializer lze provést na základě jednotlivých operací pomocí atributu DataContractFormatAttribute .

DataContractSerializerOperationBehavior a XmlSerializerOperationBehavior jsou provozní chování zodpovědné za připojení k formátování zpráv pro a DataContractSerializer v XmlSerializeruvedeném pořadí. Toto DataContractSerializerOperationBehavior chování může ve skutečnosti pracovat s libovolným serializátorem, který je odvozen od XmlObjectSerializer, včetně NetDataContractSerializer (podrobně popsaného v použití samostatné serializace). Chování volá jedno z CreateSerializer přetížení virtuální metody k získání serializátoru. Pokud chcete připojit jiný serializátor, vytvořte novou DataContractSerializerOperationBehavior podtřídu a přepište obě CreateSerializer přetížení.

Viz také