Share via


Použití kontraktů zpráv

Vývojáři obvykle při vytváření aplikací WCF (Windows Communication Foundation) věnují úzkou pozornost datovým strukturám a problémům serializace a nemusí se zabývat strukturou zpráv, ve kterých se data přenášejí. U těchto aplikací je vytváření datových kontraktů pro parametry nebo návratové hodnoty jednoduché. (Další informace najdete v tématu Určení přenosu dat v kontraktech služeb.)

Někdy je však úplná kontrola nad strukturou zprávy SOAP stejně důležitá jako kontrola nad jeho obsahem. To platí zejména v případě, že je důležitá interoperabilita nebo konkrétně kontrolovat problémy se zabezpečením na úrovni zprávy nebo části zprávy. V těchto případech můžete vytvořit kontrakt zprávy, který umožňuje zadat strukturu přesné požadované zprávy SOAP.

Toto téma popisuje, jak pomocí různých atributů kontraktu zpráv vytvořit konkrétní kontrakt zprávy pro vaši operaci.

Použití kontraktů zpráv v operacích

WCF podporuje operace modelované ve stylu vzdáleného volání procedur (RPC) nebo ve stylu zasílání zpráv. V operaci stylu RPC můžete použít libovolný serializovatelný typ a máte přístup k funkcím, které jsou k dispozici pro místní volání, například více parametrů a refout parametrů. V tomto stylu řídí forma serializace zvolená struktura dat v podkladových zprávách a modul runtime WCF vytvoří zprávy pro podporu operace. Díky tomu můžou vývojáři, kteří nejsou obeznámeni se zprávami SOAP a SOAP, rychle a snadno vytvářet a používat aplikace služeb.

Následující příklad kódu ukazuje operaci služby modelovanou ve stylu RPC.

[OperationContract]  
public BankingTransactionResponse PostBankingTransaction(BankingTransaction bt);  

Za normálních okolností je datový kontrakt dostatečný k definování schématu pro zprávy. Například v předchozím příkladu je pro většinu aplikací dostačující, pokud BankingTransaction a BankingTransactionResponse mají datové kontrakty k definování obsahu podkladových zpráv SOAP. Další informace o kontraktech dat naleznete v tématu Použití kontraktů dat.

Občas je však nutné přesně řídit strukturu zprávy SOAP přenášené přes drát. Nejběžnějším scénářem je vkládání vlastních hlaviček SOAP. Dalším běžným scénářem je definovat vlastnosti zabezpečení pro hlavičky a text zprávy, tj. rozhodnout, jestli jsou tyto prvky digitálně podepsané a zašifrované. A konečně některé zásobníky SOAP třetích stran vyžadují zprávy v určitém formátu. Operace ve stylu zasílání zpráv poskytují tento ovládací prvek.

Operace typu zasílání zpráv má maximálně jeden parametr a jednu návratovou hodnotu, kde oba typy jsou typy zpráv; to znamená, že serializují přímo do zadané struktury zpráv SOAP. Může to být libovolný typ označený typem MessageContractAttribute nebo typem Message . Následující příklad kódu ukazuje operaci podobnou předchozímu stylu RCP, ale používá styl zasílání zpráv.

Pokud jsou například BankingTransactionBankingTransactionResponse oba typy kontraktů zpráv, kód v následujících operacích je platný.

[OperationContract]  
BankingTransactionResponse Process(BankingTransaction bt);  
[OperationContract]  
void Store(BankingTransaction bt);  
[OperationContract]  
BankingTransactionResponse GetResponse();  

Následující kód je však neplatný.

[OperationContract]  
bool Validate(BankingTransaction bt);  
// Invalid, the return type is not a message contract.  
[OperationContract]  
void Reconcile(BankingTransaction bt1, BankingTransaction bt2);  
// Invalid, there is more than one parameter.  

Pro jakoukoli operaci, která zahrnuje typ kontraktu zprávy, se vyvolá výjimka, která neodpovídá jednomu z platných vzorů. Samozřejmě, operace, které nezahrnují typy kontraktů zpráv, nejsou předmětem těchto omezení.

Pokud má typ kontrakt zprávy i datový kontrakt, je při použití typu v operaci považován pouze jeho kontrakt zprávy.

Definování kontraktů zpráv

Chcete-li definovat kontrakt zprávy pro typ (to znamená definovat mapování mezi typem a obálkou SOAP), použijte MessageContractAttribute typ. Potom použijte MessageHeaderAttribute u těchto členů typu, který chcete vytvořit do hlaviček PROTOKOLU SOAP, a použijte MessageBodyMemberAttribute je u těchto členů, které chcete vytvořit, do částí textu zprávy SOAP.

Následující kód poskytuje příklad použití kontraktu zprávy.

[MessageContract]  
public class BankingTransaction  
{  
  [MessageHeader] public Operation operation;  
  [MessageHeader] public DateTime transactionDate;  
  [MessageBodyMember] private Account sourceAccount;  
  [MessageBodyMember] private Account targetAccount;  
  [MessageBodyMember] public int amount;  
}  

Při použití tohoto typu jako parametru operace se vygeneruje následující obálka SOAP:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">  
  <s:Header>  
    <h:operation xmlns:h="http://tempuri.org/" xmlns="http://tempuri.org/">Deposit</h:operation>  
    <h:transactionDate xmlns:h="http://tempuri.org/" xmlns="http://tempuri.org/">2012-02-16T16:10:00</h:transactionDate>  
  </s:Header>  
  <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">  
    <BankingTransaction xmlns="http://tempuri.org/">  
      <amount>0</amount>  
      <sourceAccount xsi:nil="true"/>  
      <targetAccount xsi:nil="true"/>  
    </BankingTransaction>  
  </s:Body>  
</s:Envelope>  

Všimněte si, že operationtransactionDate jako hlavičky SOAP a tělo SOAP se skládá z elementu BankingTransaction obálky obsahujícího sourceAccount,targetAccount a amount.

Můžete použít MessageHeaderAttribute pole MessageBodyMemberAttribute , vlastnosti a události bez ohledu na to, jestli jsou veřejná, soukromá, chráněná nebo interní.

Umožňuje MessageContractAttribute zadat WrapperName a WrapperNamespace atributy, které řídí název elementu obálky v těle zprávy SOAP. Ve výchozím nastavení se název typu kontraktu zprávy používá pro obálku a obor názvů, ve kterém je kontrakt zprávy definován http://tempuri.org/ jako výchozí obor názvů.

Poznámka:

KnownTypeAttribute atributy jsou ignorovány v kontraktech zpráv. KnownTypeAttribute V případě potřeby ji umístěte do operace, která používá příslušný kontrakt zprávy.

Řízení názvů a názvů částí záhlaví a textu

V reprezentaci protokolu SOAP kontraktu zprávy se každá hlavička a část textu mapují na element XML, který má název a obor názvů.

Ve výchozím nastavení je obor názvů stejný jako obor názvů kontraktu služby, ve kterém se zpráva účastní, a název je určen názvem člena, na který MessageHeaderAttribute se použijí atributy.MessageBodyMemberAttribute

Tyto výchozí hodnoty můžete změnit tak, že manipulujete MessageContractMemberAttribute.Name s nadřazenou MessageContractMemberAttribute.Namespace třídou MessageHeaderAttribute a MessageBodyMemberAttribute atributy.

Vezměte v úvahu třídu v následujícím příkladu kódu.

[MessageContract]  
public class BankingTransaction  
{  
  [MessageHeader] public Operation operation;  
  [MessageHeader(Namespace="http://schemas.contoso.com/auditing/2005")] public bool IsAudited;  
  [MessageBodyMember(Name="transactionData")] public BankingTransactionData theData;  
}  

V tomto příkladu je hlavička IsAudited v oboru názvů určeném v kódu a základní část, která představuje theData člen, je reprezentována elementem XML s názvem transactionData. Následující příklad ukazuje XML vygenerovaný pro tento kontrakt zprávy.

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">  
  <s:Header>  
    <h:IsAudited xmlns:h="http://schemas.contoso.com/auditing/2005" xmlns="http://schemas.contoso.com/auditing/2005">false</h:IsAudited>  
    <h:operation xmlns:h="http://tempuri.org/" xmlns="http://tempuri.org/">Deposit</h:operation>  
  </s:Header>  
  <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">  
    <AuditedBankingTransaction xmlns="http://tempuri.org/">  
      <transactionData/>  
    </AuditedBankingTransaction>  
  </s:Body>  
</s:Envelope>  

Řízení, zda jsou zabalené části těla SOAP

Ve výchozím nastavení jsou části těla SOAP serializovány uvnitř zabaleného prvku. Například následující kód ukazuje HelloGreetingMessage element obálky vygenerovaný z názvu MessageContractAttribute typu ve smlouvě zprávy pro HelloGreetingMessage zprávu.

[MessageContract]
public class HelloGreetingMessage
{
  private string localGreeting;

  [MessageBodyMember(
    Name = "Salutations",
    Namespace = "http://www.examples.com"
  )]
  public string Greeting
  {
    get { return localGreeting; }
    set { localGreeting = value; }
  }
}

/*
 The following is the request message, edited for clarity.

  <s:Envelope>
    <s:Header>
      <!-- Note: Some header content has been removed for clarity.
      <a:Action>http://GreetingMessage/Action</a:Action>
      <a:To s:mustUnderstand="1"></a:To>
    </s:Header>
    <s:Body u:Id="_0" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
      <HelloGreetingMessage xmlns="Microsoft.WCF.Documentation">
        <Salutations xmlns="http://www.examples.com">Hello.</Salutations>
      </HelloGreetingMessage>
    </s:Body>
 </s:Envelope>
 */
<MessageContract> _
Public Class HelloGreetingMessage
    Private localGreeting As String

    <MessageBodyMember(Name:="Salutations", Namespace:="http://www.examples.com")> _
    Public Property Greeting() As String
        Get
            Return localGreeting
        End Get
        Set(ByVal value As String)
            localGreeting = value
        End Set
    End Property
End Class

'  
'   The following is the request message, edited for clarity.
'    
'    <s:Envelope>
'      <s:Header>
'        <!-- Note: Some header content has been removed for clarity.
'        <a:Action>http://GreetingMessage/Action</a:Action> 
'        <a:To s:mustUnderstand="1"></a:To>
'      </s:Header>
'      <s:Body u:Id="_0" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
'        <HelloGreetingMessage xmlns="Microsoft.WCF.Documentation">
'          <Salutations xmlns="http://www.examples.com">Hello.</Salutations>
'      </s:Body>
'   </s:Envelope>
'   

Chcete-li potlačit element obálky, nastavte IsWrapped vlastnost na false. Chcete-li řídit název a obor názvů elementu obálky, použijte a WrapperNameWrapperNamespace vlastnosti.

Poznámka:

Více než jedna základní část zprávy ve zprávách, které nejsou zabalené, nevyhovuje základnímu profilu WS-I 1.1 a nedoporučuje se při navrhování nových kontraktů zpráv. V určitých konkrétních scénářích interoperability však může být nutné mít více než jednu přepsanou část textu zprávy. Pokud budete přenášet více dat v textu zprávy, doporučujeme použít výchozí (zabalený) režim. Mít více než jedno záhlaví zprávy v nezabalených zprávách je zcela přijatelné.

Použití vlastních typů uvnitř kontraktů zpráv

Každá jednotlivá hlavička zprávy a část textu zprávy je serializována (převedena na XML) pomocí zvoleného serializačního modulu pro servisní kontrakt, kde se zpráva používá. Výchozí serializační modul , XmlFormattermůže zpracovat jakýkoli typ, který má datový kontrakt, buď explicitně (pomocí System.Runtime.Serialization.DataContractAttribute) nebo implicitně (tím, že je primitivním typem, má System.SerializableAttributea tak dále). Další informace najdete v tématu Použití kontraktů dat.

V předchozím příkladu Operation musí mít datové kontrakty a BankingTransactionDatatransactionDate jsou serializovatelné, protože DateTime je primitivní (a tak má implicitní kontrakt dat).

Je však možné přepnout na jiný serializační modul, tlačítko XmlSerializer. Pokud takový přepínač provedete, měli byste zajistit, aby všechny typy používané pro záhlaví zpráv a části textu byly serializovat pomocí XmlSerializer.

Použití polí uvnitř kontraktů zpráv

Pole opakujících se prvků můžete použít ve kontraktech zpráv dvěma způsoby.

První je použít MessageHeaderAttribute nebo přímo MessageBodyMemberAttribute na poli. V tomto případě je celé pole serializováno jako jeden prvek (tj. jedna hlavička nebo jedna část těla) s více podřízenými prvky. Vezměte v úvahu třídu v následujícím příkladu.

[MessageContract]  
public class BankingDepositLog  
{  
  [MessageHeader] public int numRecords;  
  [MessageHeader] public DepositRecord[] records;  
  [MessageHeader] public int branchID;  
}  

Výsledkem jsou hlavičky SOAP podobné následujícímu.

<BankingDepositLog>  
<numRecords>3</numRecords>  
<records>  
  <DepositRecord>Record1</DepositRecord>  
  <DepositRecord>Record2</DepositRecord>  
  <DepositRecord>Record3</DepositRecord>  
</records>  
<branchID>20643</branchID>  
</BankingDepositLog>  

Alternativou k tomu je použití MessageHeaderArrayAttribute. V tomto případě je každý prvek pole serializován nezávisle a tak, aby každý prvek pole má jednu hlavičku, podobně jako následující.

<numRecords>3</numRecords>  
<records>Record1</records>  
<records>Record2</records>  
<records>Record3</records>  
<branchID>20643</branchID>  

Výchozí název položek pole je název člena, na který MessageHeaderArrayAttribute se použijí atributy.

Atribut MessageHeaderArrayAttribute dědí z objektu MessageHeaderAttribute. Má stejnou sadu funkcí jako atributy bez pole, například je možné nastavit pořadí, název a obor názvů pro pole záhlaví stejným způsobem, jako jste ho nastavili pro jednu hlavičku. Pokud vlastnost použijete Order v matici, platí pro celou matici.

Můžete použít MessageHeaderArrayAttribute pouze pole, nikoli kolekce.

Použití bajtů v kontraktech zpráv

Bajtová pole, pokud se používají s atributy bez pole (MessageBodyMemberAttribute a MessageHeaderAttribute), nejsou považovány za pole, ale jako speciální primitivní typ reprezentovaný jako data s kódováním Base64 ve výsledném XML.

Pokud použijete bajtová pole s atributem MessageHeaderArrayAttributepole , výsledky závisí na používaném serializátoru. Při výchozím serializátoru je pole reprezentováno jako jednotlivá položka pro každý bajt. Pokud je však XmlSerializer vybrána (pomocí XmlSerializerFormatAttribute smlouvy o službě), jsou bajtová pole považována za data Base64 bez ohledu na to, zda jsou použity maticové nebo nematicové atributy.

Podepisování a šifrování částí zprávy

Kontrakt zprávy může znamenat, jestli mají být hlavičky a/nebo text zprávy digitálně podepsané a zašifrované.

To se provádí nastavením MessageContractMemberAttribute.ProtectionLevel vlastnosti u MessageHeaderAttributeMessageBodyMemberAttribute atributů. Vlastnost je výčet System.Net.Security.ProtectionLevel typu a může být nastaven na None (bez šifrování nebo podpisu), Sign (pouze digitální podpis) nebo EncryptAndSign (šifrování i digitální podpis). Výchozí hodnota je EncryptAndSign.

Aby tyto funkce zabezpečení fungovaly, musíte správně nakonfigurovat vazbu a chování. Pokud použijete tyto funkce zabezpečení bez správné konfigurace (například při pokusu o podepsání zprávy bez zadání přihlašovacích údajů), vyvolá se v době ověření výjimka.

U záhlaví zpráv se úroveň ochrany určuje jednotlivě pro každou hlavičku.

U částí textu zprávy lze úroveň ochrany považovat za "minimální úroveň ochrany". Tělo má pouze jednu úroveň ochrany bez ohledu na počet částí těla. Úroveň ochrany těla je určena nejvyšším ProtectionLevel nastavením vlastnosti všech částí těla. Měli byste ale nastavit úroveň ochrany jednotlivých částí těla na skutečnou minimální požadovanou úroveň ochrany.

Vezměte v úvahu třídu v následujícím příkladu kódu.

[MessageContract]  
public class PatientRecord  
{  
   [MessageHeader(ProtectionLevel=None)] public int recordID;  
   [MessageHeader(ProtectionLevel=Sign)] public string patientName;  
   [MessageHeader(ProtectionLevel=EncryptAndSign)] public string SSN;  
   [MessageBodyMember(ProtectionLevel=None)] public string comments;  
   [MessageBodyMember(ProtectionLevel=Sign)] public string diagnosis;  
   [MessageBodyMember(ProtectionLevel=EncryptAndSign)] public string medicalHistory;  
}  

V tomto příkladu není hlavička recordID chráněna, patientName je signeda SSN je šifrovaná a podepsaná. Alespoň jedna část těla, medicalHistorybyla EncryptAndSign použita, a proto je celý text zprávy zašifrován a podepsán, i když komentáře a části těla diagnostiky určují nižší úrovně ochrany.

Akce SOAP

Standardy PROTOKOLU SOAP a souvisejících webových služeb definují vlastnost, Action která může být k dispozici pro každou odeslanou zprávu SOAP. OperationContractAttribute.Action Operace a OperationContractAttribute.ReplyAction vlastnosti řídí hodnotu této vlastnosti.

Atributy hlavičky SOAP

Standard SOAP definuje následující atributy, které mohou existovat v hlavičce:

  • Actor/Role (Actor v protokolu SOAP 1.1, Role v protokolu SOAP 1.2)

  • MustUnderstand

  • Relay

Atribut Actor určuje Role identifikátor URI (Uniform Resource Identifier) uzlu, pro který je daná hlavička určena. Atribut MustUnderstand určuje, jestli uzel, který zpracovává hlavičku, musí pochopit. Atribut Relay určuje, jestli má být hlavička předána podřízeným uzlům. WCF neprovádí žádné zpracování těchto atributů u příchozích zpráv s výjimkou atributu MustUnderstand , jak je uvedeno v části "Správa verzí kontraktu zpráv" dále v tomto tématu. Umožňuje však číst a zapisovat tyto atributy podle potřeby, jak je uvedeno v následujícím popisu.

Při odesílání zprávy se tyto atributy ve výchozím nastavení nevygenerují. Můžete to změnit dvěma způsoby. Nejprve můžete staticky nastavit atributy na libovolné požadované hodnoty změnou MessageHeaderAttribute.Actor, MessageHeaderAttribute.MustUnderstanda MessageHeaderAttribute.Relay vlastnosti, jak je znázorněno v následujícím příkladu kódu. (Všimněte si, že neexistuje žádná Role vlastnost; nastavení Actor vlastnosti vygeneruje Role atribut, pokud používáte SOAP 1.2).

[MessageContract]  
public class BankingTransaction  
{  
  [MessageHeader(Actor="http://auditingservice.contoso.com", MustUnderstand=true)] public bool IsAudited;  
  [MessageHeader] public Operation operation;  
  [MessageBodyMember] public BankingTransactionData theData;  
}  

Druhý způsob, jak řídit tyto atributy, je dynamicky prostřednictvím kódu. Toho dosáhnete tak, že do typu zabalíte požadovaný typ MessageHeader<T> záhlaví (nezapomeňte ho zaměňovat s ne generickou verzí) a použitím typu společně s MessageHeaderAttribute. Potom můžete použít vlastnosti pro MessageHeader<T> nastavení atributů SOAP, jak je znázorněno v následujícím příkladu kódu.

[MessageContract]  
public class BankingTransaction  
{  
  [MessageHeader] public MessageHeader<bool> IsAudited;  
  [MessageHeader] public Operation operation;  
  [MessageBodyMember] public BankingTransactionData theData;  
}  
// application code:  
BankingTransaction bt = new BankingTransaction();  
bt.IsAudited = new MessageHeader<bool>();  
bt.IsAudited.Content = false; // Set IsAudited header value to "false"  
bt.IsAudited.Actor="http://auditingservice.contoso.com";  
bt.IsAudited.MustUnderstand=true;  

Pokud používáte mechanismy dynamického i statického řízení, použije se statické nastavení jako výchozí, ale můžete je později přepsat pomocí dynamického mechanismu, jak je znázorněno v následujícím kódu.

[MessageHeader(MustUnderstand=true)] public MessageHeader<Person> documentApprover;  
// later on in the code:  
BankingTransaction bt = new BankingTransaction();  
bt.documentApprover = new MessageHeader<Person>();  
bt.documentApprover.MustUnderstand = false; // override the static default of 'true'  

Vytváření opakovaných hlaviček s dynamickým ovládacím prvkem atributů je povolené, jak je znázorněno v následujícím kódu.

[MessageHeaderArray] public MessageHeader<Person> documentApprovers[];  

Na straně příjmu lze čtení těchto atributů SOAP provést pouze v případě, že MessageHeader<T> třída je použita pro hlavičku v typu. ActorZkontrolujte , Relaynebo MustUnderstand vlastnosti hlavičky MessageHeader<T> typu a zjistěte nastavení atributu přijaté zprávy.

Když se zpráva přijme a pak se odešle zpět, nastavení atributu SOAP přejde pouze na zpáteční cestu pro hlavičky MessageHeader<T> typu.

Pořadí částí těla SOAP

V některých případech může být nutné řídit pořadí částí těla. Pořadí prvků těla je ve výchozím nastavení abecední, ale může být řízeno MessageBodyMemberAttribute.Order vlastností. Tato vlastnost má stejnou sémantiku jako DataMemberAttribute.Order vlastnost, s výjimkou chování ve scénářích dědičnosti (v kontraktech zpráv nejsou členy těla základního typu seřazeny před odvozenými členy textu typu). Další informace naleznete v tématu Pořadí datových členů.

V následujícím příkladu by normálně přišel jako první, amount protože je první abecedně. Order Vlastnost ji však umístí do třetí pozice.

[MessageContract]  
public class BankingTransaction  
{  
  [MessageHeader] public Operation operation;  
  [MessageBodyMember(Order=1)] public Account sourceAccount;  
  [MessageBodyMember(Order=2)] public Account targetAccount;  
  [MessageBodyMember(Order=3)] public int amount;  
}  

Správa verzí kontraktů zpráv

Někdy může být potřeba změnit kontrakty zpráv. Například nová verze aplikace může do zprávy přidat další hlavičku. Při odesílání z nové verze do starého systému musí systém zpracovat další hlavičku, stejně jako chybějící hlavičku při přechodu do jiného směru.

Následující pravidla platí pro hlavičky správy verzí:

  • WCF nemá objekt na chybějící hlavičky – odpovídající členy jsou ponechány na jejich výchozích hodnotách.

  • WCF také ignoruje neočekávané nadbytečné hlavičky. Jedinou výjimkou tohoto pravidla je, že pokud má MustUnderstand další hlavička nastavený true atribut v příchozí zprávě SOAP – v tomto případě je vyvolán výjimka, protože hlavička, která musí být srozumitelná, nelze zpracovat.

Těla zpráv mají podobná pravidla správy verzí – chybějící i další části textu zprávy se ignorují.

Aspekty dědičnosti

Typ kontraktu zprávy může dědit z jiného typu, pokud základní typ má také kontrakt zprávy.

Při vytváření nebo přístupu ke zprávě pomocí typu kontraktu zprávy, který dědí z jiných typů kontraktů zpráv, platí následující pravidla:

  • Všechny hlavičky zpráv v hierarchii dědičnosti se shromažďují společně, aby vytvořily úplnou sadu záhlaví zprávy.

  • Všechny části textu zprávy v hierarchii dědičnosti se shromažďují dohromady a tvoří celý text zprávy. Části těla jsou seřazeny podle obvyklých pravidel řazení (podle MessageBodyMemberAttribute.Order vlastnosti a potom abecedy), bez relevance pro jejich místo v hierarchii dědičnosti. Použití dědičnosti kontraktů zpráv, kde se části textu zprávy vyskytují na více úrovních stromu dědičnosti, důrazně nedoporučujeme. Pokud základní třída a odvozená třída definují hlavičku nebo základní část se stejným názvem, člen ze základní třídy se použije k uložení hodnoty této hlavičky nebo základní části těla.

Vezměte v úvahu třídy v následujícím příkladu kódu.

[MessageContract]  
public class PersonRecord  
{  
  [MessageHeader(Name="ID")] public int personID;  
  [MessageBodyMember] public string patientName;  
}  
  
[MessageContract]  
public class PatientRecord : PersonRecord  
{  
  [MessageHeader(Name="ID")] public int patientID;  
  [MessageBodyMember] public string diagnosis;  
}  

Třída PatientRecord popisuje zprávu s jedním záhlavím s názvem ID. Záhlaví odpovídá členu personID , nikoli členu patientID , protože je zvolen základní člen. patientID V tomto případě je tedy pole zbytečné. Text zprávy obsahuje diagnosis prvek následovaný patientName elementem, protože je to abecední pořadí. Všimněte si, že příklad ukazuje vzor, který se důrazně nedoporučuje: základní i odvozené kontrakty zpráv mají části textu zprávy.

Důležité informace o WSDL

Při generování kontraktu WSDL (Web Services Description Language) ze služby, která používá kontrakty zpráv, je důležité si uvědomit, že ve výsledném WSDL se neprojeví všechny funkce kontraktu zpráv. Zvažte následující skutečnosti:

  • WSDL nemůže vyjádřit koncept pole hlaviček. Při vytváření zpráv s polem hlaviček pomocí MessageHeaderArrayAttributevýsledného WSDL se místo pole odráží pouze jedno záhlaví.

  • Výsledný dokument WSDL nemusí odrážet některé informace na úrovni ochrany.

  • Typ zprávy vygenerovaný ve WSDL má stejný název jako název třídy typu kontraktu zprávy.

  • Při použití stejného kontraktu zpráv ve více operacích se v dokumentu WSDL vygeneruje více typů zpráv. Názvy jsou jedinečné přidáním čísel 2, 3 atd. pro následné použití. Při importu zpět WSDL se vytvoří více typů kontraktů zpráv a jsou shodné s výjimkou jejich názvů.

Důležité informace o kódování SOAP

WCF umožňuje použít starší styl kódování SOAP XML, ale jeho použití se nedoporučuje. Při použití tohoto stylu (nastavením Use vlastnosti na Encoded použitou System.ServiceModel.XmlSerializerFormatAttribute na servisní kontrakt), platí následující další aspekty:

  • Záhlaví zpráv nejsou podporována; to znamená, že atribut MessageHeaderAttribute a atribut MessageHeaderArrayAttribute pole nejsou kompatibilní s kódováním SOAP.

  • Pokud kontrakt zprávy není zabalen, to znamená, že pokud je vlastnost IsWrapped nastavena na false, kontrakt zprávy může mít pouze jednu základní část.

  • Název elementu obálky pro kontrakt zprávy požadavku musí odpovídat názvu operace. WrapperName K tomu použijte vlastnost kontraktu zprávy.

  • Název elementu obálky pro kontrakt zprávy odpovědi musí být stejný jako název operace přípony "Response". WrapperName K tomu použijte vlastnost kontraktu zprávy.

  • Kódování SOAP zachovává odkazy na objekty. Představte si například následující kód.

    [MessageContract(WrapperName="updateChangeRecord")]  
    public class ChangeRecordRequest  
    {  
      [MessageBodyMember] Person changedBy;  
      [MessageBodyMember] Person changedFrom;  
      [MessageBodyMember] Person changedTo;  
    }  
    
    [MessageContract(WrapperName="updateChangeRecordResponse")]  
    public class ChangeRecordResponse  
    {  
      [MessageBodyMember] Person changedBy;  
      [MessageBodyMember] Person changedFrom;  
      [MessageBodyMember] Person changedTo;  
    }  
    
    // application code:  
    ChangeRecordRequest cr = new ChangeRecordRequest();  
    Person p = new Person("John Doe");  
    cr.changedBy=p;  
    cr.changedFrom=p;  
    cr.changedTo=p;  
    

Po serializaci zprávy pomocí kódování changedFrom SOAP a changedTo neobsahují vlastní kopie p, ale místo toho ukažte na kopii uvnitř elementu changedBy .

Faktory ovlivňující výkon

Každá hlavička zprávy a část textu zprávy se serializuje nezávisle na ostatních. Proto lze stejné obory názvů deklarovat znovu pro každou část záhlaví a těla. Pokud chcete zlepšit výkon, zejména pokud jde o velikost zprávy na drátě, sloučit více záhlaví a částí textu do jedné hlavičky nebo základní části. Například místo následujícího kódu:

[MessageContract]  
public class BankingTransaction  
{  
  [MessageHeader] public Operation operation;  
  [MessageBodyMember] public Account sourceAccount;  
  [MessageBodyMember] public Account targetAccount;  
  [MessageBodyMember] public int amount;  
}  

Použijte tento kód.

[MessageContract]  
public class BankingTransaction  
{  
  [MessageHeader] public Operation operation;  
  [MessageBodyMember] public OperationDetails details;  
}  
  
[DataContract]  
public class OperationDetails  
{  
  [DataMember] public Account sourceAccount;  
  [DataMember] public Account targetAccount;  
  [DataMember] public int amount;  
}  

Asynchronní kontrakty a kontrakty zpráv založené na událostech

Pokyny k návrhu pro stav asynchronního modelu založeného na událostech, že pokud je vrácena více než jedna hodnota, vrátí se jedna hodnota jako Result vlastnost a ostatní se vrátí jako vlastnosti objektu EventArgs . Jedním z těchto výsledků je, že pokud klient importuje metadata pomocí možností asynchronního příkazu založeného na událostech a operace vrátí více než jednu hodnotu, výchozí EventArgs objekt vrátí jednu hodnotu jako Result vlastnost a zbytek jsou vlastnosti objektu EventArgs .

Pokud chcete přijmout objekt zprávy jako Result vlastnost a mít vrácené hodnoty jako vlastnosti tohoto objektu /messageContract , použijte možnost příkazu. Tím se vygeneruje podpis, který vrátí zprávu odpovědi jako Result vlastnost objektu EventArgs . Všechny interní návratové hodnoty jsou vlastnosti objektu zprávy odpovědi.

Viz také