Delen via


Berichtcontracten gebruiken

Meestal besteden ontwikkelaars bij het bouwen van WCF-toepassingen (Windows Communication Foundation) aandacht aan de gegevensstructuren en serialisatieproblemen en hoeven ze zich niet bezig te houden met de structuur van de berichten waarin de gegevens worden uitgevoerd. Voor deze toepassingen is het maken van gegevenscontracten voor de parameters of retourwaarden eenvoudig. (Zie voor meer informatie Gegevensoverdracht opgeven in servicecontracten.)

Soms is volledige controle over de structuur van een SOAP-bericht echter net zo belangrijk als de controle over de inhoud ervan. Dit geldt met name wanneer interoperabiliteit belangrijk is of specifiek beveiligingsproblemen op het niveau van het bericht of berichtonderdeel wilt beheren. In deze gevallen kunt u een berichtcontract maken waarmee u de structuur van het exacte SOAP-bericht kunt opgeven dat nodig is.

In dit onderwerp wordt beschreven hoe u de verschillende kenmerken van het berichtcontract gebruikt om een specifiek berichtcontract voor uw bewerking te maken.

Berichtcontracten gebruiken in bewerkingen

WCF ondersteunt bewerkingen die zijn gemodelleerd op de RPC-stijl (Remote Procedure Call) of de berichtstijl. In een RPC-bewerking kunt u elk serialiseerbare type gebruiken en hebt u toegang tot de functies die beschikbaar zijn voor lokale aanroepen, zoals meerdere parameters en refout parameters. In deze stijl bepaalt de gekozen vorm van serialisatie de structuur van de gegevens in de onderliggende berichten en maakt de WCF-runtime de berichten om de bewerking te ondersteunen. Hierdoor kunnen ontwikkelaars die niet bekend zijn met SOAP- en SOAP-berichten snel en eenvoudig servicetoepassingen maken en gebruiken.

In het volgende codevoorbeeld ziet u een servicebewerking die is gemodelleerd in de RPC-stijl.

[OperationContract]  
public BankingTransactionResponse PostBankingTransaction(BankingTransaction bt);  

Normaal gesproken is een gegevenscontract voldoende om het schema voor de berichten te definiëren. In het voorgaande voorbeeld is het bijvoorbeeld voldoende voor de meeste toepassingen als BankingTransaction er BankingTransactionResponse gegevenscontracten zijn om de inhoud van de onderliggende SOAP-berichten te definiëren. Zie Gegevenscontracten gebruiken voor meer informatie over gegevenscontracten.

Af en toe is het echter noodzakelijk om precies te bepalen hoe de structuur van het SOAP-bericht via de draad wordt verzonden. Het meest voorkomende scenario hiervoor is het invoegen van aangepaste SOAP-headers. Een ander veelvoorkomend scenario is het definiëren van beveiligingseigenschappen voor de kopteksten en hoofdtekst van het bericht, dus om te bepalen of deze elementen digitaal zijn ondertekend en versleuteld. Ten slotte vereisen sommige SOAP-stacks van derden dat berichten een specifieke indeling hebben. Bewerkingen in berichtenstijl bieden dit besturingselement.

Een berichtstijlbewerking heeft ten hoogste één parameter en één retourwaarde waarbij beide typen berichttypen zijn; Dat wil gezegd, ze serialiseren rechtstreeks in een opgegeven SOAP-berichtstructuur. Dit kan elk type zijn dat is gemarkeerd met het MessageContractAttribute type of het Message type. In het volgende codevoorbeeld ziet u een bewerking die vergelijkbaar is met de voorgaande RCP-stijl, maar die gebruikmaakt van de berichtstijl.

Als en BankingTransactionResponse beide typen berichtencontracten zijn, BankingTransaction is de code in de volgende bewerkingen bijvoorbeeld geldig.

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

De volgende code is echter ongeldig.

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

Er wordt een uitzondering gegenereerd voor een bewerking waarbij een berichtcontracttype is betrokken en die geen van de geldige patronen volgt. Natuurlijk zijn bewerkingen waarbij geen berichtcontracttypen betrokken zijn, niet onderhevig aan deze beperkingen.

Als een type zowel een berichtcontract als een gegevenscontract heeft, wordt alleen het berichtcontract beschouwd wanneer het type wordt gebruikt in een bewerking.

Berichtcontracten definiëren

Als u een berichtcontract wilt definiëren voor een type (dat wil zeggen, als u de toewijzing tussen het type en een SOAP-envelop wilt definiëren), past u het MessageContractAttribute toe op het type. Pas vervolgens de MessageHeaderAttribute leden toe van het type dat u wilt maken in SOAP-headers en pas de MessageBodyMemberAttribute leden toe die u wilt maken in delen van de SOAP-hoofdtekst van het bericht.

De volgende code bevat een voorbeeld van het gebruik van een berichtcontract.

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

Wanneer u dit type gebruikt als een bewerkingsparameter, wordt de volgende SOAP-envelop gegenereerd:

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

U ziet dat operation en transactionDate worden weergegeven als SOAP-headers en de SOAP-hoofdtekst uit een wrapper-element BankingTransaction dat sourceAccount,targetAccount, en amount.

U kunt de MessageHeaderAttribute en MessageBodyMemberAttribute op alle velden, eigenschappen en gebeurtenissen toepassen, ongeacht of ze openbaar, privé, beveiligd of intern zijn.

Hiermee MessageContractAttribute kunt u de kenmerken WrapperName en WrapperNamespace opgeven waarmee de naam van het wrapper-element in de hoofdtekst van het SOAP-bericht wordt bepaald. De naam van het berichtcontracttype wordt standaard gebruikt voor de wrapper en de naamruimte waarin het berichtcontract is gedefinieerd http://tempuri.org/ , wordt gebruikt als de standaardnaamruimte.

Notitie

KnownTypeAttribute kenmerken worden genegeerd in berichtcontracten. Als een KnownTypeAttribute bericht vereist is, plaatst u deze op de bewerking die het betreffende berichtcontract gebruikt.

Namen en naamruimten van koptekst- en hoofdonderdelen beheren

In de SOAP-weergave van een berichtcontract wordt elk kop- en hoofdtekstonderdeel toegewezen aan een XML-element met een naam en een naamruimte.

De naamruimte is standaard hetzelfde als de naamruimte van het servicecontract waaraan het bericht deelneemt en de naam wordt bepaald door de lidnaam waarop de MessageHeaderAttribute of de MessageBodyMemberAttribute kenmerken worden toegepast.

U kunt deze standaardinstellingen wijzigen door de MessageContractMemberAttribute.Name en MessageContractMemberAttribute.Namespace (op de bovenliggende klasse van de MessageHeaderAttribute en MessageBodyMemberAttribute kenmerken) te bewerken.

Bekijk de klasse in het volgende codevoorbeeld.

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

In dit voorbeeld bevindt de IsAudited header zich in de naamruimte die is opgegeven in de code en het hoofdgedeelte dat het theData lid vertegenwoordigt, wordt vertegenwoordigd door een XML-element met de naam transactionData. Hieronder ziet u de XML die voor dit berichtcontract is gegenereerd.

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

Bepalen of de SOAP-lichaamsdelen zijn verpakt

Standaard worden de SOAP-hoofdonderdelen geserialiseerd in een verpakt element. De volgende code toont bijvoorbeeld het HelloGreetingMessage wrapper-element dat is gegenereerd op basis van de naam van het MessageContractAttribute type in het berichtcontract voor het HelloGreetingMessage bericht.

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

Als u het wrapper-element wilt onderdrukken, stelt u de IsWrapped eigenschap in op false. Als u de naam en de naamruimte van het wrapper-element wilt beheren, gebruikt u de WrapperName en WrapperNamespace eigenschappen.

Notitie

Het hebben van meer dan één berichttekstgedeelte in berichten die niet zijn verpakt, voldoet niet aan WS-I Basic Profile 1.1 en wordt niet aanbevolen bij het ontwerpen van nieuwe berichtcontracten. Het kan echter nodig zijn om meer dan één niet-uitgepakt berichttekstonderdeel te hebben in bepaalde specifieke interoperabiliteitsscenario's. Als u meer dan één stukje gegevens in een berichttekst wilt verzenden, is het raadzaam om de standaardmodus (verpakt) te gebruiken. Het is volledig acceptabel om meer dan één berichtkop in niet-uitgepakte berichten te hebben.

Aangepaste typen binnen berichtcontracten gebruiken

Elk afzonderlijk berichtkop- en berichttekstonderdeel wordt geserialiseerd (omgezet in XML) met behulp van de gekozen serialisatie-engine voor het servicecontract waarin het bericht wordt gebruikt. De standaardserialisatie-engine, de XmlFormatter, kan elk type verwerken dat een gegevenscontract heeft, expliciet (door de System.Runtime.Serialization.DataContractAttribute) of impliciet (door een primitief type te zijn, de System.SerializableAttribute, enzovoort). Zie Gegevenscontracten gebruiken voor meer informatie.

In het voorgaande voorbeeld moeten de Operation typen BankingTransactionData een gegevenscontract hebben en transactionDate serialiseerbaar zijn omdat DateTime dit een primitief is (en dus een impliciet gegevenscontract heeft).

Het is echter mogelijk om over te schakelen naar een andere serialisatie-engine, de XmlSerializer. Als u een dergelijke schakeloptie maakt, moet u ervoor zorgen dat alle typen die worden gebruikt voor berichtkoppen en hoofdonderdelen serialiseerbaar zijn met behulp van de XmlSerializer.

Matrices binnen berichtcontracten gebruiken

U kunt matrices van herhalende elementen in berichtcontracten op twee manieren gebruiken.

De eerste is het gebruik van een MessageHeaderAttribute of een MessageBodyMemberAttribute rechtstreeks op de matrix. In dit geval wordt de hele matrix geserialiseerd als één element (dat wil gezegd, één koptekst of één hoofdgedeelte) met meerdere onderliggende elementen. Bekijk de klasse in het volgende voorbeeld.

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

Dit resulteert in SOAP-headers die er ongeveer als volgt uitzien.

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

Een alternatief hiervoor is het gebruik van de MessageHeaderArrayAttribute. In dit geval wordt elk matrixelement onafhankelijk geserialiseerd en heeft elk matrixelement één header, vergelijkbaar met de volgende.

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

De standaardnaam voor matrixvermeldingen is de naam van het lid waarop de MessageHeaderArrayAttribute kenmerken worden toegepast.

Het MessageHeaderArrayAttribute kenmerk neemt over van de MessageHeaderAttribute. Het heeft dezelfde set functies als de niet-matrixkenmerken, bijvoorbeeld het is mogelijk om de volgorde, naam en naamruimte in te stellen voor een matrix met headers op dezelfde manier als u deze instelt voor één koptekst. Wanneer u de Order eigenschap voor een matrix gebruikt, is deze van toepassing op de hele matrix.

U kunt de MessageHeaderArrayAttribute enige toepassen op matrices, niet op verzamelingen.

Bytematrices gebruiken in berichtcontracten

Bytematrices, wanneer ze worden gebruikt met de niet-matrixkenmerken (MessageBodyMemberAttribute en MessageHeaderAttribute), worden niet behandeld als matrices, maar als een speciaal primitief type dat wordt weergegeven als met Base64 gecodeerde gegevens in de resulterende XML.

Wanneer u bytematrices met het matrixkenmerk MessageHeaderArrayAttributegebruikt, zijn de resultaten afhankelijk van de serialisatiefunctie die wordt gebruikt. Met de standaardserialisatie wordt de matrix weergegeven als een afzonderlijke vermelding voor elke byte. Wanneer de XmlSerializer selectie echter is ingeschakeld (met behulp van het XmlSerializerFormatAttribute servicecontract), worden bytematrices behandeld als Base64-gegevens, ongeacht of de matrix- of niet-matrixkenmerken worden gebruikt.

Delen van het bericht ondertekenen en versleutelen

Een berichtcontract kan aangeven of de kopteksten en/of hoofdtekst van het bericht digitaal moeten worden ondertekend en versleuteld.

Dit wordt gedaan door de eigenschap in te MessageContractMemberAttribute.ProtectionLevel stellen op de MessageHeaderAttribute en MessageBodyMemberAttribute kenmerken. De eigenschap is een opsomming van het System.Net.Security.ProtectionLevel type en kan worden ingesteld op None (geen versleuteling of handtekening), Sign (alleen digitale handtekening) of EncryptAndSign (zowel versleuteling als een digitale handtekening). De standaardwaarde is EncryptAndSign.

Deze beveiligingsfuncties werken alleen als u de binding en het gedrag goed configureert. Als u deze beveiligingsfuncties zonder de juiste configuratie gebruikt (bijvoorbeeld wanneer u een bericht probeert te ondertekenen zonder uw referenties op te geven), wordt er een uitzondering gegenereerd tijdens de validatie.

Voor berichtkoppen wordt het beveiligingsniveau afzonderlijk bepaald voor elke koptekst.

Voor berichttekstonderdelen kan het beveiligingsniveau worden beschouwd als het 'minimale beveiligingsniveau'. Het lichaam heeft slechts één beveiligingsniveau, ongeacht het aantal lichaamsdelen. Het beveiligingsniveau van het lichaam wordt bepaald door de hoogste ProtectionLevel eigenschapsinstelling van alle lichaamsdelen. U moet echter het beveiligingsniveau van elk hoofdgedeelte instellen op het daadwerkelijke vereiste minimale beveiligingsniveau.

Bekijk de klasse in het volgende codevoorbeeld.

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

In dit voorbeeld is de recordID header niet beveiligd, patientName is signeden SSN is deze versleuteld en ondertekend. Ten minste één hoofdgedeelte, medicalHistoryis EncryptAndSign toegepast en dus is de hele berichttekst versleuteld en ondertekend, ook al geven de opmerkingen en diagnosegedeelten lagere beschermingsniveaus op.

SOAP-actie

SOAP en gerelateerde webservicesstandaarden definiëren een eigenschap die kan worden aangeroepen Action voor elk SOAP-bericht dat wordt verzonden. De bewerkingen OperationContractAttribute.Action en OperationContractAttribute.ReplyAction eigenschappen bepalen de waarde van deze eigenschap.

SOAP-headerkenmerken

De SOAP-standaard definieert de volgende kenmerken die op een header kunnen bestaan:

  • Actor/Role (Actor in SOAP 1.1, Role in SOAP 1.2)

  • MustUnderstand

  • Relay

Het Actor of Role kenmerk geeft de URI (Uniform Resource Identifier) op van het knooppunt waarvoor een bepaalde header is bedoeld. Het MustUnderstand kenmerk geeft aan of het knooppunt dat de header verwerkt, dit moet begrijpen. Het Relay kenmerk geeft aan of de header moet worden doorgestuurd naar downstreamknooppunten. WCF voert geen verwerking van deze kenmerken uit voor binnenkomende berichten, met uitzondering van het MustUnderstand kenmerk, zoals opgegeven in de sectie Versiebeheer van berichtcontract verderop in dit onderwerp. U kunt deze kenmerken echter zo nodig lezen en schrijven, zoals in de volgende beschrijving.

Bij het verzenden van een bericht worden deze kenmerken niet standaard verzonden. U kunt dit op twee manieren wijzigen. Ten eerste kunt u de kenmerken statisch instellen op gewenste waarden door de MessageHeaderAttribute.Actor, MessageHeaderAttribute.MustUnderstanden MessageHeaderAttribute.Relay eigenschappen te wijzigen, zoals wordt weergegeven in het volgende codevoorbeeld. (Houd er rekening mee dat er geen Role eigenschap is. Als u de Actor eigenschap instelt, wordt het Role kenmerk verzonden als u SOAP 1.2 gebruikt).

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

De tweede manier om deze kenmerken te beheren, is dynamisch via code. U kunt dit bereiken door het gewenste headertype in het MessageHeader<T> type te verpakken (vergeet niet dit type te verwarren met de niet-algemene versie) en door het type samen met het MessageHeaderAttributetype te gebruiken. Vervolgens kunt u eigenschappen op de MessageHeader<T> functie gebruiken om de SOAP-kenmerken in te stellen, zoals wordt weergegeven in het volgende codevoorbeeld.

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

Als u zowel de dynamische als de statische besturingsmechanismen gebruikt, worden de statische instellingen als standaard gebruikt, maar kunnen ze later worden overschreven met behulp van het dynamische mechanisme, zoals wordt weergegeven in de volgende code.

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

Het maken van herhaalde headers met dynamisch kenmerkbeheer is toegestaan, zoals wordt weergegeven in de volgende code.

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

Aan de ontvangstzijde kunnen deze SOAP-kenmerken alleen worden gelezen als de MessageHeader<T> klasse wordt gebruikt voor de header in het type. Bekijk de Actor, Relayof MustUnderstand eigenschappen van een koptekst van het MessageHeader<T> type om de kenmerkinstellingen voor het ontvangen bericht te detecteren.

Wanneer een bericht wordt ontvangen en vervolgens teruggezonden, gaan de SOAP-kenmerkinstellingen alleen terug voor kopteksten van het MessageHeader<T> type.

Volgorde van SOAP-hoofdonderdelen

In sommige gevallen moet u mogelijk de volgorde van de lichaamsdelen bepalen. De volgorde van de hoofdtekstelementen is standaard alfabetisch, maar kan worden bepaald door de MessageBodyMemberAttribute.Order eigenschap. Deze eigenschap heeft dezelfde semantiek als de DataMemberAttribute.Order eigenschap, met uitzondering van het gedrag in overnamescenario's (in berichtcontracten worden hoofdtekstleden van het basistype niet gesorteerd vóór de leden van het afgeleide type). Zie Order voor gegevenslid voor meer informatie.

In het volgende voorbeeld amount zou normaal gesproken eerst komen omdat het eerst alfabetisch is. De eigenschap plaatst deze Order echter op de derde positie.

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

Versiebeheer van berichtcontract

Soms moet u mogelijk berichtcontracten wijzigen. Een nieuwe versie van uw toepassing kan bijvoorbeeld een extra koptekst toevoegen aan een bericht. Wanneer het systeem vervolgens van de nieuwe versie naar de oude verzendt, moet het systeem een extra header en een ontbrekende header verwerken wanneer deze in de andere richting gaat.

De volgende regels zijn van toepassing op headers voor versiebeheer:

  • WCF maakt geen bezwaar tegen de ontbrekende headers. De bijbehorende leden blijven op hun standaardwaarden staan.

  • WCF negeert ook onverwachte extra headers. De enige uitzondering op deze regel is als de extra header een MustUnderstand kenmerk heeft ingesteld true op in het binnenkomende SOAP-bericht. In dit geval wordt er een uitzondering gegenereerd omdat een header die moet worden begrepen, niet kan worden verwerkt.

Berichtteksten hebben vergelijkbare versiebeheerregels. Zowel ontbrekende als aanvullende berichttekstonderdelen worden genegeerd.

Overwegingen voor overname

Een berichtcontracttype kan overnemen van een ander type, zolang het basistype ook een berichtcontract heeft.

Wanneer u een bericht maakt of opent met behulp van een berichtcontracttype dat wordt overgenomen van andere berichtcontracttypen, zijn de volgende regels van toepassing:

  • Alle berichtkoppen in de overnamehiërarchie worden samen verzameld om de volledige set kopteksten voor het bericht te vormen.

  • Alle hoofdtekstonderdelen van het bericht in de overnamehiërarchie worden samen verzameld om de volledige hoofdtekst van het bericht te vormen. De hoofdtekstdelen worden geordend volgens de gebruikelijke volgorderegels (op MessageBodyMemberAttribute.Order eigenschap en vervolgens alfabetisch), zonder relevantie voor hun plaats in de overnamehiërarchie. Het gebruik van overname van berichtencontract waarbij berichttekstdelen op meerdere niveaus van de overnamestructuur voorkomen, wordt sterk afgeraden. Als een basisklasse en een afgeleide klasse een kop- of hoofdtekstonderdeel met dezelfde naam definiëren, wordt het lid uit de basisklasse gebruikt om de waarde van die kop- of hoofdtekst op te slaan.

Bekijk de klassen in het volgende codevoorbeeld.

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

De PatientRecord klasse beschrijft een bericht met één header met de naam ID. De header komt overeen met het personID en niet het patientID lid, omdat het meest basislid is gekozen. patientID Het veld is dus nutteloos in dit geval. De hoofdtekst van het bericht bevat het diagnosis element gevolgd door het patientName element, omdat dat de alfabetische volgorde is. In het voorbeeld ziet u een patroon dat sterk wordt afgeraden: zowel de basis- als de afgeleide berichtcontracten hebben berichttekstonderdelen.

WSDL-overwegingen

Bij het genereren van een WSDL-contract (Web Services Description Language) van een service die gebruikmaakt van berichtcontracten, is het belangrijk te onthouden dat niet alle functies van het berichtcontract worden weergegeven in de resulterende WSDL. Overweeg het volgende:

  • WSDL kan het concept van een matrix van headers niet uitdrukken. Bij het maken van berichten met een matrix met headers met behulp van de MessageHeaderArrayAttribute, geeft de resulterende WSDL slechts één header weer in plaats van de matrix.

  • Het resulterende WSDL-document bevat mogelijk geen informatie op beveiligingsniveau.

  • Het berichttype dat is gegenereerd in de WSDL heeft dezelfde naam als de klassenaam van het type berichtcontract.

  • Wanneer u hetzelfde berichtcontract in meerdere bewerkingen gebruikt, worden er meerdere berichttypen gegenereerd in het WSDL-document. De namen worden uniek gemaakt door de getallen '2', '3' enzovoort toe te voegen voor volgende toepassingen. Wanneer u de WSDL importeert, worden er meerdere typen berichtencontract gemaakt en zijn ze identiek, met uitzondering van hun namen.

Overwegingen voor SOAP-codering

MET WCF kunt u de verouderde SOAP-coderingsstijl van XML gebruiken, maar het gebruik ervan wordt niet aanbevolen. Wanneer u deze stijl gebruikt (door de eigenschap Encoded in Use te stellen op het System.ServiceModel.XmlSerializerFormatAttribute toegepaste servicecontract), zijn de volgende aanvullende overwegingen van toepassing:

  • De berichtkoppen worden niet ondersteund; dit betekent dat het kenmerk MessageHeaderAttribute en het matrixkenmerk MessageHeaderArrayAttribute niet compatibel zijn met SOAP-codering.

  • Als het berichtcontract niet is verpakt, dat wil zeggen, als de eigenschap IsWrapped is ingesteld false, kan het berichtcontract slechts één hoofdgedeelte hebben.

  • De naam van het wrapper-element voor het aanvraagberichtcontract moet overeenkomen met de naam van de bewerking. Gebruik hiervoor de WrapperName eigenschap van het berichtcontract.

  • De naam van het wrapper-element voor het antwoordberichtcontract moet gelijk zijn aan de naam van de bewerking die is achtervoegsel 'Antwoord'. Gebruik hiervoor de WrapperName eigenschap van het berichtcontract.

  • Soap-codering behoudt objectverwijzingen. Denk bijvoorbeeld aan de volgende code.

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

Nadat het bericht is geserialiseerd met SOAP-codering en changedTo geen eigen kopieën van phet bericht bevat, changedFrom maar in plaats daarvan verwijst u naar de kopie in het changedBy element.

Prestatieoverwegingen

Elk berichtkop- en berichttekstonderdeel wordt onafhankelijk van de andere geserialiseerd. Daarom kunnen dezelfde naamruimten opnieuw worden gedeclareerd voor elk kop- en hoofdtekstonderdeel. Om de prestaties te verbeteren, met name wat betreft de grootte van het bericht op de draad, voegt u meerdere headers en hoofdonderdelen samen in één kop- of hoofdtekstonderdeel. Bijvoorbeeld, in plaats van de volgende code:

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

Gebruik deze code.

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

Asynchrone Asynchrone en berichtcontracten op basis van gebeurtenissen

De ontwerprichtlijnen voor de asynchrone modelstatus op basis van gebeurtenissen dat als er meer dan één waarde wordt geretourneerd, één waarde wordt geretourneerd als de Result eigenschap en de andere als eigenschappen voor het EventArgs object worden geretourneerd. Een resultaat hiervan is dat als een client metagegevens importeert met behulp van de asynchrone opdrachtopties op basis van gebeurtenissen en de bewerking meer dan één waarde retourneert, retourneert het standaardobject EventArgs één waarde als de Result eigenschap en de rest zijn eigenschappen van het EventArgs object.

Als u het berichtobject wilt ontvangen als de Result eigenschap en de geretourneerde waarden als eigenschappen voor dat object wilt hebben, gebruikt u de /messageContract opdrachtoptie. Hiermee wordt een handtekening gegenereerd die het antwoordbericht retourneert als de Result eigenschap van het EventArgs object. Alle interne retourwaarden zijn vervolgens eigenschappen van het antwoordberichtobject.

Zie ook