Megosztás a következőn keresztül:


Üzenetszerződések használata

A Windows Communication Foundation (WCF) alkalmazások létrehozásakor a fejlesztők általában nagy figyelmet fordítanak az adatstruktúrákra és a szerializálási problémákra, és nem kell foglalkozniuk az adatok hordozásának üzeneteinek szerkezetével. Ezekben az alkalmazásokban egyszerű adatszerződéseket létrehozni a paraméterekhez vagy a visszaadott értékekhez. (További információ: Adatátvitel megadása a szolgáltatási szerződésekben.)

Néha azonban a SOAP-üzenetek szerkezetének teljes vezérlése ugyanolyan fontos, mint a tartalom szabályozása. Ez különösen akkor igaz, ha az együttműködés fontos, vagy kifejezetten az üzenet vagy üzenetrész szintjén szabályozza a biztonsági problémákat. Ezekben az esetekben létrehozhat egy üzenetszerződést, amely lehetővé teszi a szükséges pontos SOAP-üzenet szerkezetének megadását.

Ez a témakör azt ismerteti, hogyan hozhat létre egy adott üzenetszerződést a művelethez a különböző üzenetszerződési attribútumokkal.

Üzenetszerződések használata a műveletekben

A WCF támogatja a távoli eljáráshívási (RPC) stílusban vagy az üzenetkezelési stílusban modellezett műveleteket. Egy RPC-stílusú műveletben bármilyen szerializálható típust használhat, és hozzáférhet a helyi hívásokhoz elérhető funkciókhoz, például több paraméterhez és ref out paraméterhez. Ebben a stílusban a választott szerializálási forma szabályozza az alapul szolgáló üzenetekben lévő adatok szerkezetét, és a WCF-futtatókörnyezet létrehozza az üzeneteket a művelet támogatásához. Így a SOAP- és SOAP-üzeneteket nem ismerő fejlesztők gyorsan és egyszerűen hozhatnak létre és használhatnak szolgáltatásalkalmazásokat.

Az alábbi kódpéldában egy RPC-stílusban modellezett szolgáltatásművelet látható.

[OperationContract]  
public BankingTransactionResponse PostBankingTransaction(BankingTransaction bt);  

Az adatszerződés általában elegendő az üzenetek sémájának meghatározásához. Az előző példában például elegendő, ha BankingTransaction BankingTransactionResponse a legtöbb alkalmazás adatszerződéssel rendelkezik az alapul szolgáló SOAP-üzenetek tartalmának meghatározásához. További információ az adatszerződésekről: Adatszerződések használata.

Időnként azonban pontosan szabályozni kell, hogy a SOAP-üzenet struktúrája hogyan terjedt át a vezetéken. Ennek leggyakoribb forgatókönyve az egyéni SOAP-fejlécek beszúrása. Egy másik gyakori forgatókönyv az üzenet fejléceinek és törzsének biztonsági tulajdonságainak meghatározása, vagyis annak eldöntése, hogy ezek az elemek digitálisan aláírtak és titkosítva vannak-e. Végül néhány külső SOAP-veremhez az üzeneteknek egy adott formátumban kell lenniük. Az üzenetkezelési stílusú műveletek biztosítják ezt a vezérlőt.

Az üzenetkezelési stílusú műveletek legfeljebb egy paraméterrel és egy visszatérési értékkel rendelkeznek, ahol mindkét típus üzenettípus; vagyis közvetlenül egy adott SOAP-üzenetstruktúrába szerializálják őket. Ez lehet bármilyen típus, amely a típussal vagy Message a MessageContractAttribute típussal van megjelölve. Az alábbi kódpéldában az előző RCP-stílushoz hasonló, de az üzenetkezelési stílust használó művelet látható.

Ha például BankingTransaction BankingTransactionResponse mindkét típus üzenetszerződés, akkor az alábbi műveletek kódja érvényes.

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

A következő kód azonban érvénytelen.

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

Kivételt jelent minden olyan művelet, amely üzenetszerződés-típust tartalmaz, és amely nem követi az érvényes minták egyikét. Természetesen az üzenetszerződés-típusokat nem tartalmazó műveletekre nem vonatkoznak ezek a korlátozások.

Ha egy típus üzenetszerződéssel és adatszerződéssel is rendelkezik, akkor csak az üzenetszerződést veszi figyelembe, amikor a típust egy műveletben használják.

Üzenetszerződések meghatározása

Egy típus üzenetszerződésének definiálásához (azaz a típus és a SOAP-boríték közötti leképezés meghatározásához) alkalmazza a MessageContractAttribute típust. Ezután alkalmazza azokat a MessageHeaderAttribute tagokat a SOAP-fejlécekbe, és alkalmazza a MessageBodyMemberAttribute kívánt tagokat az üzenet SOAP törzsének részeire.

Az alábbi kód egy üzenetszerződés használatát szemlélteti.

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

Ha ezt a típust műveleti paraméterként használja, a rendszer a következő SOAP-borítékot hozza létre:

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

Figyelje meg, hogy operation a SOAP fejlécekként és a SOAP törzse egy burkolóelemből áll, amely sourceAccounttartalmazza a (éstargetAccountamount) elemetBankingTransaction.transactionDate

Az összes MessageBodyMemberAttribute mezőt, tulajdonságot és eseményt alkalmazhatjaMessageHeaderAttribute, függetlenül attól, hogy nyilvánosak, privátak, védettek vagy belsőek.

Ez MessageContractAttribute lehetővé teszi a Burkolónév és a Burkolónévtér attribútumok megadását, amelyek a SOAP-üzenet törzsében lévő burkolóelem nevét vezérlik. Alapértelmezés szerint a rendszer az üzenetszerződés típusát használja a burkolóhoz, és az üzenetszerződést definiáló http://tempuri.org/ névtér lesz az alapértelmezett névtér.

Feljegyzés

KnownTypeAttribute az attribútumok figyelmen kívül lesznek hagyva az üzenetszerződésekben. KnownTypeAttribute Ha szükséges, helyezze el a szóban forgó üzenetszerződést használó műveletre.

Élőfej- és törzsrésznevek és névterek szabályozása

Az üzenetszerződés SOAP-ábrázolásakor minden fejléc és törzsrész egy névvel és névtérrel rendelkező XML-elemhez lesz leképezve.

A névtér alapértelmezés szerint megegyezik annak a szolgáltatási szerződésnek a névterével, amelyben az üzenet részt vesz, és a nevet annak a tagnak a neve határozza meg, amelyre az MessageHeaderAttribute MessageBodyMemberAttribute attribútumokat alkalmazza.

Ezeket az alapértelmezett értékeket módosíthatja az MessageContractMemberAttribute.Name és MessageContractMemberAttribute.Namespace (a szülőosztály és MessageBodyMemberAttribute az MessageHeaderAttribute attribútumok) módosításával.

Vegye figyelembe az osztályt a következő kód példában.

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

Ebben a példában a fejléc a IsAudited kódban megadott névtérben van, a tagot képviselő theData törzsrészt pedig egy XML-elem jelöli a névvel transactionData. Az alábbiakban az üzenetszerződéshez létrehozott XML látható.

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

Annak szabályozása, hogy a SOAP törzsrészek burkolva vannak-e

Alapértelmezés szerint a SOAP törzsrészek egy burkolt elemen belül szerializálva vannak. Az alábbi kód például az HelloGreetingMessage üzenethez tartozó üzenetszerződésben szereplő típus nevéből MessageContractAttribute létrehozott burkolóelemet jeleníti meg HelloGreetingMessage .

[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>
'   

A burkolóelem letiltásához állítsa a tulajdonságot a IsWrapped következőre false: . A burkolóelem nevének és névterének szabályozásához használja a tulajdonságokat és WrapperNamespace a WrapperName tulajdonságokat.

Feljegyzés

A nem burkolt üzenetek több üzenettörzsrésze nem felel meg a WS-I Basic Profile 1.1 szabványnak, és nem ajánlott új üzenetszerződések tervezésekor. Előfordulhat azonban, hogy bizonyos együttműködési forgatókönyvekben több, nem írt üzenettörzs is szükséges. Ha egy üzenettörzsben egynél több adatot szeretne továbbítani, ajánlott az alapértelmezett (burkolt) módot használni. Egynél több üzenetfejléc használata a nem írt üzenetekben teljesen elfogadható.

Egyéni típusok használata üzenetszerződésen belül

Az egyes üzenetfejlécek és üzenettörzsrészek szerializálva vannak (XML-be vannak kapcsolva) a választott szerializálási motor használatával ahhoz a szolgáltatási szerződéshez, amelyben az üzenetet használják. Az alapértelmezett szerializációs motor, a XmlFormatter, bármilyen adatszerződéssel rendelkező típust képes kezelni explicit módon (a System.Runtime.Serialization.DataContractAttribute) vagy implicit módon (primitív típus, rendelkezik a System.SerializableAttributestb.). További információ: Adatszerződések használata.

Az előző példában a Operation típusoknak adatszerződéssel BankingTransactionData kell rendelkezniük, és transactionDate szerializálhatónak kell lenniük, mert DateTime primitívek (és implicit adatszerződéssel is rendelkeznek).

Azonban válthat egy másik szerializálási motorra, a XmlSerializer. Ha ilyen kapcsolót hoz létre, győződjön meg arról, hogy az üzenetfejlécekhez és a törzsrészekhez használt összes típus szerializálható a XmlSerializer.

Tömbök használata üzenetszerződéseken belül

Az üzenetszerződésekben ismétlődő elemek tömbjei kétféleképpen használhatók.

Az első egy vagy egy MessageBodyMemberAttribute közvetlen tömb használataMessageHeaderAttribute. Ebben az esetben a teljes tömb egy elemként (vagyis egy fejlécként vagy egy törzsrészként) szerializálva van, több gyermekelemet tartalmazó elemként. Vegye figyelembe az osztályt az alábbi példában.

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

Ez a SOAP-fejlécekben az alábbihoz hasonló eredményt ad.

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

Ennek egyik alternatíva a MessageHeaderArrayAttribute. Ebben az esetben minden tömbelem egymástól függetlenül szerializálva van, és így minden tömbelemnek egy fejléce van, hasonlóan az alábbiakhoz.

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

A tömbbejegyzések alapértelmezett neve annak a tagnak a neve, amelyre az MessageHeaderArrayAttribute attribútumokat alkalmazza.

Az MessageHeaderArrayAttribute attribútum öröklődik a MessageHeaderAttribute. Ugyanazokkal a funkciókkal rendelkezik, mint a nem tömbök attribútumai, például a fejléctömbök sorrendjét, nevét és névterét ugyanúgy lehet beállítani, mint egy fejléchez. Ha egy tömbön használja a Order tulajdonságot, az a teljes tömbre vonatkozik.

Az MessageHeaderArrayAttribute egyetlen tömböt tömbökre alkalmazhatja, gyűjteményekre nem.

Bájttömbök használata üzenetszerződésekben

A nem tömb attribútumokkal (MessageBodyMemberAttribute és MessageHeaderAttribute) használt bájttömböket nem tömbökként, hanem egy speciális primitív típusként kezelik, amely base64 kódolású adatként jelenik meg az eredményként kapott XML-ben.

Ha bájttömböket használ a tömbattribútummal MessageHeaderArrayAttribute, az eredmények a használt szerializálótól függenek. Az alapértelmezett szerializáló esetében a tömb minden bájthoz egyéni bejegyzésként jelenik meg. Ha azonban a XmlSerializer ki van választva (a szolgáltatási szerződés alapján), a XmlSerializerFormatAttribute bájttömbök Base64-adatokként lesznek kezelve, függetlenül attól, hogy a tömb vagy a nem tömb attribútumokat használják-e.

Az üzenet részeinek aláírása és titkosítása

Az üzenetszerződés jelezheti, hogy az üzenet fejléceinek és/vagy törzsének digitálisan alá kell-e írnia és titkosítania kell-e.

Ez a tulajdonság és MessageBodyMemberAttribute az MessageContractMemberAttribute.ProtectionLevel MessageHeaderAttribute attribútumok beállításával végezhető el. A tulajdonság a System.Net.Security.ProtectionLevel típus számbavétele, amely (titkosítás vagy aláírás nélkül), (csak digitális aláírás esetén) Sign vagy EncryptAndSign (titkosítás és digitális aláírás nélkül) állítható be None . Az alapértelmezett érték EncryptAndSign.

Ahhoz, hogy ezek a biztonsági funkciók működjenek, megfelelően kell konfigurálnia a kötést és a viselkedést. Ha ezeket a biztonsági funkciókat a megfelelő konfiguráció nélkül használja (például megkísérli aláírni az üzenetet a hitelesítő adatok megadásával), a rendszer kivételt jelez az érvényesítési időpontban.

Az üzenetfejlécek esetében a védelmi szint külön-külön van meghatározva az egyes fejlécekhez.

Az üzenettörzs részeinél a védelmi szint a "minimális védelmi szint" lehet. A test csak egy védelmi szinttel rendelkezik, függetlenül a testrészek számától. A test védelmi szintjét az összes testrész legmagasabb ProtectionLevel tulajdonságbeállítása határozza meg. Az egyes testrészek védelmi szintjét azonban a szükséges minimális védelmi szintre kell állítani.

Vegye figyelembe az osztályt a következő kód példában.

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

Ebben a példában a recordID fejléc nem védett, patientName titkosítva signedSSN és aláírva van. Legalább egy törzsrészt medicalHistoryalkalmaz, EncryptAndSign és így a teljes üzenettörzs titkosítva és aláírva van, annak ellenére, hogy a megjegyzések és a diagnosztikai törzsrészek alacsonyabb védelmi szinteket határoznak meg.

SOAP-művelet

A SOAP és a kapcsolódó webszolgáltatások szabványai meghatároznak egy olyan tulajdonságot Action , amely minden elküldött SOAP-üzenethez jelen lehet. A művelet OperationContractAttribute.Action és OperationContractAttribute.ReplyAction a tulajdonságok vezérli ennek a tulajdonságnak az értékét.

SOAP-fejlécattribútumok

A SOAP szabvány az alábbi attribútumokat határozza meg, amelyek egy fejlécen lehetnek:

  • Actor/Role (Actor a SOAP 1.1-ben, Role a SOAP 1.2-ben)

  • MustUnderstand

  • Relay

Az Actor vagy Role attribútum annak a csomópontnak az egységes erőforrás-azonosítóját (URI) adja meg, amelyhez egy adott fejlécet szánnak. Az MustUnderstand attribútum megadja, hogy a fejlécet feldolgozó csomópontnak meg kell-e értenie. Az Relay attribútum megadja, hogy a fejléc tovább legyen-e továbbítva az alsóbb rétegbeli csomópontokra. A WCF nem végzi el ezeknek az attribútumoknak a feldolgozását a bejövő üzeneteken, kivéve az MustUnderstand attribútumot, a jelen témakör későbbi, "Üzenetszerződés verziószámozása" című szakaszában meghatározottak szerint. Lehetővé teszi azonban, hogy szükség esetén elolvassa és megírja ezeket az attribútumokat, ahogyan az alábbi leírásban is szerepel.

Üzenet küldésekor ezek az attribútumok alapértelmezés szerint nem lesznek kibocsátva. Ezt kétféleképpen módosíthatja. Először is statikusan beállíthatja az attribútumokat a kívánt értékekre a , MessageHeaderAttribute.MustUnderstandés MessageHeaderAttribute.Relay a MessageHeaderAttribute.Actortulajdonságok módosításával, ahogyan az az alábbi kód példában látható. (Vegye figyelembe, hogy nincs Role tulajdonság; ha a SOAP 1.2-t használja, a Actor tulajdonság kibocsátja az Role attribútumot.

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

Az attribútumok szabályozásának második módja a kódon keresztüli dinamikus vezérlés. Ezt úgy érheti el, hogy becsomagolja a kívánt fejléctípust a MessageHeader<T> típusba (ne keverje össze ezt a típust a nem általános verzióval), és használja a típust a MessageHeaderAttribute. Ezután a tulajdonságokat MessageHeader<T> a SOAP attribútumok beállításához használhatja, ahogyan az alábbi kód példában is látható.

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

Ha a dinamikus és a statikus vezérlési mechanizmust is használja, a statikus beállításokat a rendszer alapértelmezettként használja, de később felül lehet bírálni a dinamikus mechanizmus használatával, ahogyan az az alábbi kódban is látható.

[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'  

A dinamikus attribútumvezérlővel rendelkező ismétlődő fejlécek létrehozása engedélyezett, ahogy az az alábbi kódban is látható.

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

A fogadó oldalon ezek a SOAP-attribútumok olvasása csak akkor végezhető el, ha az MessageHeader<T> osztályt a típus fejlécéhez használják. ActorA kapott üzenet attribútumbeállításainak felderítéséhez vizsgálja meg a MessageHeader<T> típus fejlécének , Relayvagy MustUnderstand tulajdonságait.

Amikor egy üzenet érkezik, majd visszaküldi őket, a SOAP attribútum beállításai csak a típus fejléceinél MessageHeader<T> lépnek végig.

SOAP törzsrészek sorrendje

Bizonyos körülmények között előfordulhat, hogy szabályoznia kell a testrészek sorrendjét. A törzselemek sorrendje alapértelmezés szerint betűrendes, de a MessageBodyMemberAttribute.Order tulajdonság szabályozható. Ez a tulajdonság ugyanazokkal a szemantikával rendelkezik, mint a DataMemberAttribute.Order tulajdonság, kivéve az öröklési forgatókönyvek viselkedését (az üzenetszerződésekben az alaptípus törzstagjai nem lesznek rendezve a származtatott típus törzstagjai előtt). További információ: Adattagsorrend.

A következő példában általában azért lenne az első, amount mert betűrendben az első. A tulajdonság azonban a Order harmadik helyre helyezi.

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

Üzenetszerződés verziószámozása

Időnként előfordulhat, hogy módosítania kell az üzenetszerződéseket. Az alkalmazás új verziója például további fejlécet adhat hozzá egy üzenethez. Ezután az új verzióról a régire való küldéskor a rendszernek egy további fejlécet, valamint egy hiányzó fejlécet kell kezelnie, amikor a másik irányba halad.

A verziószámozási fejlécekre a következő szabályok vonatkoznak:

  • A WCF nem tiltakozik a hiányzó fejlécek ellen – a megfelelő tagok az alapértelmezett értékükön maradnak.

  • A WCF figyelmen kívül hagyja a váratlan további fejléceket is. A szabály egyetlen kivétele az, ha a további fejléc attribútuma a bejövő SOAP-üzenetben van MustUnderstand beállítva true – ebben az esetben a rendszer kivételt küld, mert egy megértendő fejlécet nem lehet feldolgozni.

Az üzenettörzsek hasonló verziószámozási szabályokkal rendelkeznek – a rendszer figyelmen kívül hagyja a hiányzó és a további üzenettörzsrészeket is.

Öröklési szempontok

Az üzenetszerződés típusa örökölhető egy másik típustól, feltéve, hogy az alaptípus is rendelkezik üzenetszerződéssel.

Amikor más üzenetszerződéstípusoktól öröklő üzenetszerződés-típussal hoz létre vagy fér hozzá egy üzenethez, a következő szabályok érvényesek:

  • Az öröklési hierarchiában lévő összes üzenetfejléc össze lesz gyűjtve az üzenet teljes fejléckészletének létrehozásához.

  • Az öröklési hierarchia összes üzenettörzsrésze össze lesz gyűjtve a teljes üzenettörzs létrehozásához. A törzsrészek a szokásos rendezési szabályok szerint vannak rendezve ( MessageBodyMemberAttribute.Order tulajdonság, majd betűrend szerint), és nincs jelentősége az öröklési hierarchiában való helyüknek. Erősen elriasztja az üzenetszerződés öröklését, ha az üzenet törzsrészei az öröklési fa több szintjén fordulnak elő. Ha egy alaposztály és egy származtatott osztály azonos nevű fejlécet vagy törzsrészt határoz meg, a rendszer az alapszintű osztály tagját használja az adott fejléc vagy törzsrész értékének tárolására.

Vegye figyelembe az alábbi kód példában szereplő osztályokat.

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

Az PatientRecord osztály egy olyan üzenetet ír le, amelynek egy fejléce van.ID A fejléc nem a tagnak, hanem a personID patientID tagnak felel meg, mert a rendszer a legtöbb tagot választja ki. Így a patientID mező ebben az esetben haszontalan. Az üzenet törzse tartalmazza az diagnosis elemet, amelyet az patientName elem követ, mivel ez az betűrend. Figyelje meg, hogy a példa egy erősen elriasztott mintát mutat: mind az alap, mind a származtatott üzenetszerződések üzenettörzs-részekkel rendelkeznek.

WSDL-szempontok

Amikor egy üzenetszerződést használó szolgáltatásból létrehoz egy Web Services Description Language (WSDL) szerződést, fontos megjegyezni, hogy nem minden üzenetszerződési funkció jelenik meg az eredményként kapott WSDL-ben. Vegye figyelembe a következő szempontokat:

  • A WSDL nem tudja kifejezni a fejléctömb fogalmát. Ha a fejléctömböt használó MessageHeaderArrayAttributeüzeneteket hoz létre, az eredményként kapott WSDL a tömb helyett csak egy fejlécet tükröz.

  • Az eredményként kapott WSDL-dokumentum nem feltétlenül tükrözi a védelmi szintű információkat.

  • A WSDL-ben létrehozott üzenettípus neve megegyezik az üzenetszerződés típusának osztálynevével.

  • Ha ugyanazt az üzenetszerződést több műveletben használja, a WSDL-dokumentumban több üzenettípus jön létre. A nevek egyedivé teszik a "2", "3" stb. számokat a későbbi felhasználásokhoz. A WSDL visszaimportálásakor több üzenetszerződés-típus jön létre, és a nevük kivételével azonosak.

SOAP-kódolási szempontok

A WCF lehetővé teszi az XML régi SOAP kódolási stílusának használatát, azonban használata nem ajánlott. Ha ezt a stílust használja (a Use szolgáltatásszerződésre alkalmazott tulajdonság Encoded System.ServiceModel.XmlSerializerFormatAttribute beállításával), a következő további szempontokat kell figyelembe vennie:

  • Az üzenetfejlécek nem támogatottak; Ez azt jelenti, hogy az attribútum MessageHeaderAttribute és a tömbattribútum MessageHeaderArrayAttribute nem kompatibilis a SOAP kódolással.

  • Ha az üzenetszerződés nincs burkolva, azaz ha a tulajdonság IsWrapped értéke be van állítva false, az üzenetszerződésnek csak egy törzsrésze lehet.

  • A kérelemüzenet-szerződés burkolóelemének nevének meg kell egyeznie a művelet nevével. Ehhez használja az WrapperName üzenetszerződés tulajdonságát.

  • A válaszüzenet-szerződés burkolóelemének neve megegyezik a "Válasz" utótagú művelet nevével. Ehhez használja az WrapperName üzenetszerződés tulajdonságát.

  • A SOAP-kódolás megőrzi az objektumhivatkozásokat. Vegyük például az alábbi kódot.

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

Miután szerializálta az üzenetet SOAP kódolással, changedFrom és changedTo nem tartalmazza a saját másolatait p, hanem az elemen belüli changedBy másolatra mutat.

A teljesítménnyel kapcsolatos megfontolások

Minden üzenetfejléc és üzenettörzsrész szerializálva van a többitől függetlenül. Ezért ugyanazokat a névtereket minden fejléchez és törzsrészhez újra deklarálhatja. A teljesítmény javítása érdekében, különösen a vezetéken lévő üzenet méretében, egyesítse több fejlécet és törzsrészt egyetlen fejlécbe vagy törzsrészbe. Például a következő kód helyett:

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

Használja ezt a kódot.

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

Eseményalapú aszinkron és üzenetszerződések

Az eseményalapú aszinkron modell tervezési irányelvei szerint ha egynél több értéket ad vissza, a rendszer egy értéket ad vissza tulajdonságként Result , a többit pedig tulajdonságokként az EventArgs objektumon. Ennek egyik eredménye, hogy ha egy ügyfél az eseményalapú aszinkron parancsbeállítások használatával importál metaadatokat, és a művelet több értéket ad vissza, az alapértelmezett EventArgs objektum egy értéket ad vissza tulajdonságként Result , a többi pedig az EventArgs objektum tulajdonságait.

Ha tulajdonságként szeretné megkapni az Result üzenetobjektumot, és a visszaadott értékeket tulajdonságokként szeretné megkapni az objektumon, használja a parancsbeállítást /messageContract . Ez létrehoz egy aláírást, amely visszaadja a válaszüzenetet az Result objektum tulajdonságaként EventArgs . Ezután az összes belső visszatérési érték a válaszüzenet-objektum tulajdonságai.

Lásd még