Delen via


Servicecontracten ontwerpen

In dit onderwerp wordt beschreven wat servicecontracten zijn, hoe deze worden gedefinieerd, welke bewerkingen beschikbaar zijn (en de gevolgen voor de onderliggende berichtuitwisseling), welke gegevenstypen worden gebruikt en andere problemen waarmee u bewerkingen kunt ontwerpen die voldoen aan de vereisten van uw scenario.

Een servicecontract maken

Services maken een aantal bewerkingen beschikbaar. Definieer in WCF-toepassingen (Windows Communication Foundation) de bewerkingen door een methode te maken en deze te markeren met het OperationContractAttribute kenmerk. Als u vervolgens een servicecontract wilt maken, groepeert u uw bewerkingen door ze te declareren in een interface die is gemarkeerd met het ServiceContractAttribute kenmerk of door ze te definiëren in een klasse die is gemarkeerd met hetzelfde kenmerk. (Zie voor een basisvoorbeeld Procedure: Een servicecontract definiëren.)

Methoden die geen kenmerk hebben OperationContractAttribute , zijn geen servicebewerkingen en worden niet weergegeven door WCF-services.

In dit onderwerp worden de volgende beslissingspunten beschreven bij het ontwerpen van een servicecontract:

  • Of u klassen of interfaces wilt gebruiken.

  • De gegevenstypen opgeven die u wilt uitwisselen.

  • De typen uitwisselingspatronen die u kunt gebruiken.

  • Of u expliciete beveiligingsvereisten kunt maken die deel uitmaken van het contract.

  • De beperkingen voor bewerkingsinvoer en -uitvoer.

Klassen of interfaces

Beide klassen en interfaces vertegenwoordigen een groepering van functionaliteit en daarom kunnen beide worden gebruikt om een WCF-servicecontract te definiëren. Het wordt echter aanbevolen om interfaces te gebruiken omdat ze rechtstreeks servicecontracten modelleren. Zonder een implementatie definiëren interfaces niet meer dan een groepering van methoden met bepaalde handtekeningen. Implementeer een servicecontractinterface en u hebt een WCF-service geïmplementeerd.

Alle voordelen van beheerde interfaces zijn van toepassing op servicecontractinterfaces:

  • Servicecontractinterfaces kunnen een willekeurig aantal andere servicecontractinterfaces uitbreiden.

  • Eén klasse kan een willekeurig aantal servicecontracten implementeren door deze servicecontractinterfaces te implementeren.

  • U kunt de implementatie van een servicecontract wijzigen door de interface-implementatie te wijzigen, terwijl het servicecontract hetzelfde blijft.

  • U kunt uw service versien door de oude interface en de nieuwe te implementeren. Oude clients maken verbinding met de oorspronkelijke versie, terwijl nieuwere clients verbinding kunnen maken met de nieuwere versie.

Notitie

Bij het overnemen van andere servicecontractinterfaces kunt u geen bewerkingseigenschappen overschrijven, zoals de naam of naamruimte. Als u dit probeert te doen, maakt u een nieuwe bewerking in het huidige servicecontract.

Zie Een service maken met een contractinterface voor een voorbeeld van het gebruik van een interface.

U kunt echter een klasse gebruiken om een servicecontract te definiëren en dat contract tegelijkertijd te implementeren. Het voordeel van het maken van uw services door respectievelijk de klasse en de methoden op de klasse toe te passen en OperationContractAttribute rechtstreeks toe te passen ServiceContractAttribute op de klasse, is snelheid en eenvoud. De nadelen zijn dat beheerde klassen geen ondersteuning bieden voor meerdere overnames, waardoor ze slechts één servicecontract tegelijk kunnen implementeren. Bovendien wijzigt elke wijziging van de klasse- of methodehandtekeningen het openbare contract voor die service, waardoor niet-gewijzigde clients uw service kunnen gebruiken. Zie Servicecontracten implementeren voor meer informatie.

Zie How to: Create a Service with a Contract Class (Een service maken met een contractklasse) voor een voorbeeld waarin een klasse wordt gebruikt om een servicecontract te maken en dit tegelijkertijd te implementeren.

Op dit moment moet u het verschil begrijpen tussen het definiëren van uw servicecontract met behulp van een interface en met behulp van een klasse. De volgende stap is bepalen welke gegevens kunnen worden doorgestuurd tussen een service en de bijbehorende clients.

Parameters en retourwaarden

Elke bewerking heeft een retourwaarde en een parameter, zelfs als deze zijn void. In tegenstelling tot een lokale methode, waarbij u verwijzingen naar objecten van het ene object naar het andere kunt doorgeven, geven servicebewerkingen geen verwijzingen door naar objecten. In plaats daarvan geven ze kopieën van de objecten door.

Dit is belangrijk omdat elk type dat in een parameter of retourwaarde wordt gebruikt, serialiseerbaar moet zijn; Dat wil gezegd, het moet mogelijk zijn om een object van dat type te converteren naar een stroom van bytes en van een stroom van bytes naar een object.

Primitieve typen zijn standaard serialiseerbaar, net als veel typen in .NET Framework.

Notitie

De waarde van de parameternamen in de bewerkingshandtekening maakt deel uit van het contract en zijn hoofdlettergevoelig. Als u dezelfde parameternaam lokaal wilt gebruiken maar de naam in de gepubliceerde metagegevens wilt wijzigen, raadpleegt u de System.ServiceModel.MessageParameterAttribute.

Gegevenscontracten

Servicegeoriënteerde toepassingen zoals WCF-toepassingen (Windows Communication Foundation) zijn ontworpen voor samenwerking met het breedst mogelijke aantal clienttoepassingen op zowel Microsoft- als niet-Microsoft-platforms. Voor de meest uitgebreide interoperabiliteit is het raadzaam om uw typen te markeren met de DataContractAttribute en DataMemberAttribute kenmerken om een gegevenscontract te maken. Dit is het deel van het servicecontract waarin de gegevens worden beschreven die door uw servicebewerkingen worden uitgewisseld.

Gegevenscontracten zijn contracten in opt-in-stijl: er wordt geen type of gegevenslid geserialiseerd, tenzij u het kenmerk van het gegevenscontract expliciet toepast. Gegevenscontracten zijn niet gerelateerd aan het toegangsbereik van de beheerde code: leden van persoonlijke gegevens kunnen elders worden geserialiseerd en elders worden verzonden om openbaar te worden geopend. (Zie voor een eenvoudig voorbeeld van een gegevenscontract Procedure: Een basisgegevenscontract maken voor een klasse of structuur.) WCF verwerkt de definitie van de onderliggende SOAP-berichten die de functionaliteit van de bewerking mogelijk maken, evenals de serialisatie van uw gegevenstypen in en uit de hoofdtekst van de berichten. Zolang uw gegevenstypen serialiseerbaar zijn, hoeft u niet na te denken over de onderliggende infrastructuur voor het uitwisselen van berichten bij het ontwerpen van uw bewerkingen.

Hoewel de typische WCF-toepassing gebruikmaakt van de DataContractAttribute en DataMemberAttribute kenmerken voor het maken van gegevenscontracten voor bewerkingen, kunt u andere serialisatiemechanismen gebruiken. De standaard ISerializable, SerializableAttributeen IXmlSerializable mechanismen werken allemaal om de serialisatie van uw gegevenstypen af te handelen in de onderliggende SOAP-berichten die ze van de ene toepassing naar de andere overbrengen. U kunt meer serialisatiestrategieën gebruiken als voor uw gegevenstypen speciale ondersteuning is vereist. Zie Gegevensoverdracht opgeven in servicecontracten voor meer informatie over de keuzes voor serialisatie van gegevenstypen in WCF-toepassingen.

Parameters toewijzen en waarden retourneren aan berichtenuitwisseling

Servicebewerkingen worden ondersteund door een onderliggende uitwisseling van SOAP-berichten die toepassingsgegevens heen en weer overdragen, naast de gegevens die de toepassing nodig heeft om bepaalde standaardbeveiligings-, transactie- en sessiegerelateerde functies te ondersteunen. Omdat dit het geval is, bepaalt de handtekening van een servicebewerking een bepaald onderliggend message exchange-patroon (MEP) dat ondersteuning kan bieden voor de gegevensoverdracht en de functies die een bewerking vereist. U kunt drie patronen opgeven in het WCF-programmeermodel: aanvraag-/antwoord-, eenrichtings- en dubbelzijdige berichtpatronen.

Aanvraag/antwoord

Een aanvraag-/antwoordpatroon is een patroon waarin een afzender van een aanvraag (een clienttoepassing) een antwoord ontvangt waarmee de aanvraag is gecorreleerd. Dit is de standaard-MEP omdat deze een bewerking ondersteunt waarin een of meer parameters worden doorgegeven aan de bewerking en een retourwaarde wordt doorgegeven aan de aanroeper. In het volgende C#-codevoorbeeld ziet u bijvoorbeeld een eenvoudige servicebewerking die één tekenreeks gebruikt en een tekenreeks retourneert.

[OperationContractAttribute]  
string Hello(string greeting);  

Hier volgt de equivalente Visual Basic-code.

<OperationContractAttribute()>  
Function Hello (ByVal greeting As String) As String  

Deze bewerkingshandtekening bepaalt de vorm van onderliggende berichtuitwisseling. Als er geen correlatie bestaat, kan WCF niet bepalen voor welke bewerking de retourwaarde is bedoeld.

Houd er rekening mee dat, tenzij u een ander onderliggend berichtpatroon opgeeft, zelfs servicebewerkingen die worden geretourneerd void (Nothing in Visual Basic) aanvraag-/antwoordberichtenuitwisselingen zijn. Het resultaat voor uw bewerking is dat, tenzij een client de bewerking asynchroon aanroept, de client stopt met verwerken totdat het retourbericht wordt ontvangen, ook al is dat bericht leeg in het normale geval. In het volgende C#-codevoorbeeld ziet u een bewerking die pas wordt geretourneerd als de client een leeg bericht heeft ontvangen als reactie.

[OperationContractAttribute]  
void Hello(string greeting);  

Hier volgt de equivalente Visual Basic-code.

<OperationContractAttribute()>  
Sub Hello (ByVal greeting As String)  

Het voorgaande voorbeeld kan de prestaties en reactiesnelheid van de client vertragen als het lang duurt om de bewerking uit te voeren, maar er zijn voordelen voor het aanvragen/beantwoorden van bewerkingen, zelfs wanneer ze retourneren void. Het meest voor de hand liggende is dat SOAP-fouten kunnen worden geretourneerd in het antwoordbericht, wat aangeeft dat er een servicegerelateerde fout is opgetreden, ongeacht of er communicatie of verwerking plaatsvindt. SOAP-fouten die zijn opgegeven in een servicecontract, worden als object FaultException<TDetail> doorgegeven aan de clienttoepassing, waarbij de typeparameter het type is dat is opgegeven in het servicecontract. Dit maakt het eenvoudig om clients op de hoogte te stellen van foutvoorwaarden in WCF-services. Zie Fouten opgeven en afhandelen in contracten en services voor meer informatie over uitzonderingen, SOAP-fouten en foutafhandeling. Zie Een aanvraag-antwoordcontract maken voor een voorbeeld van een aanvraag-/antwoordservice en -client. Zie Request-Reply Services voor meer informatie over problemen met het aanvraag-antwoordpatroon.

One-way

Als de client van een WCF-servicetoepassing niet moet wachten tot de bewerking is voltooid en SOAP-fouten niet verwerkt, kan de bewerking een patroon voor een eenrichtingsbericht opgeven. Een eenrichtingsbewerking is een bewerking waarin een client een bewerking aanroept en doorgaat met verwerken nadat WCF het bericht naar het netwerk schrijft. Dit betekent meestal dat, tenzij de gegevens die in het uitgaande bericht worden verzonden, zeer groot zijn, de client bijna onmiddellijk wordt uitgevoerd (tenzij er een fout optreedt bij het verzenden van de gegevens). Dit type berichtuitwisselingspatroon ondersteunt gebeurtenisachtig gedrag van een client naar een servicetoepassing.

Een berichtuitwisseling waarin één bericht wordt verzonden en geen berichten worden ontvangen, kan geen ondersteuning bieden voor een servicebewerking waarmee een andere retourwaarde dan void; in dit geval een InvalidOperationException uitzondering wordt gegenereerd.

Geen retourbericht betekent ook dat er geen SOAP-fout kan worden geretourneerd om eventuele fouten in verwerking of communicatie aan te geven. (Voor het communiceren van foutinformatie wanneer bewerkingen in één richting zijn vereist, is een dubbelzijdig berichtuitwisselingspatroon vereist.)

Als u een eenrichtingsberichtuitwisseling wilt opgeven voor een bewerking die wordt geretourneerd void, stelt u de IsOneWay eigenschap truein op , zoals in het volgende C#-codevoorbeeld.

[OperationContractAttribute(IsOneWay=true)]  
void Hello(string greeting);  

Hier volgt de equivalente Visual Basic-code.

<OperationContractAttribute(IsOneWay := True)>  
Sub Hello (ByVal greeting As String)  

Deze methode is identiek aan het voorgaande aanvraag-/antwoordvoorbeeld, maar het instellen van de IsOneWay eigenschap betekent true dat hoewel de methode identiek is, de servicebewerking geen retourbericht verzendt en clients onmiddellijk worden geretourneerd zodra het uitgaande bericht is overgedragen aan de kanaallaag. Zie Een voorbeeld : Een eenrichtingscontract maken. Zie One-Way Services voor meer informatie over het eenrichtingspatroon.

Duplex

Een dubbelzijdig patroon wordt gekenmerkt door de mogelijkheid van zowel de service als de client om berichten onafhankelijk naar elkaar te verzenden, ongeacht of er sprake is van een eenrichtings- of aanvraag-/antwoordberichten. Deze vorm van tweerichtingscommunicatie is handig voor services die rechtstreeks met de client moeten communiceren of een asynchrone ervaring bieden aan beide zijden van een berichtuitwisseling, inclusief gedrag zoals gebeurtenissen.

Het dubbelzijdige patroon is iets complexer dan de aanvraag/antwoord- of eenrichtingspatronen vanwege het extra mechanisme voor communicatie met de client.

Als u een dubbelzijdig contract wilt ontwerpen, moet u ook een callback-contract ontwerpen en het type callback-contract toewijzen aan de CallbackContract eigenschap van het ServiceContractAttribute kenmerk dat uw servicecontract markeert.

Als u een dubbelzijdig patroon wilt implementeren, moet u een tweede interface maken die de methodedeclaraties bevat die op de client worden aangeroepen.

Voor een voorbeeld van het maken van een service en een client die toegang heeft tot die service, raadpleegt u Het volgende: Een duplexcontract maken en procedures: toegang krijgen tot services met een duplex-contract. Zie Duplex voor een werkend voorbeeld. Zie Duplex Services voor meer informatie over problemen met het gebruik van dubbelzijdige contracten.

Let op

Wanneer een service een dubbelzijdig bericht ontvangt, wordt het ReplyTo element in dat binnenkomende bericht bekeken om te bepalen waar het antwoord moet worden verzonden. Als het kanaal dat wordt gebruikt voor het ontvangen van het bericht niet is beveiligd, kan een niet-vertrouwde client een schadelijk bericht verzenden met een doelcomputer ReplyTo, wat leidt tot een Denial of Service (DOS) van die doelmachine.

Parameters Out en Ref

In de meeste gevallen kunt u parameters (ByValin Visual Basic) en parameters (in Visual Basic) en refout parameters (ByRefin Visual Basic) gebruikenin. Omdat beide out en ref parameters aangeven dat gegevens worden geretourneerd door een bewerking, geeft een bewerkingshandtekening zoals het volgende aan dat een aanvraag-/antwoordbewerking vereist is, ook al retourneert de bewerkingshandtekening void.

[ServiceContractAttribute]  
public interface IMyContract  
{  
  [OperationContractAttribute]  
  public void PopulateData(ref CustomDataType data);  
}  

Hier volgt de equivalente Visual Basic-code.

<ServiceContractAttribute()> _  
Public Interface IMyContract  
  <OperationContractAttribute()> _  
  Public Sub PopulateData(ByRef data As CustomDataType)  
End Interface  

De enige uitzonderingen zijn gevallen waarin uw handtekening een bepaalde structuur heeft. U kunt de binding bijvoorbeeld alleen gebruiken NetMsmqBinding om met clients te communiceren als de methode die wordt gebruikt om een bewerking te declareren, retourneertvoid; er kan geen uitvoerwaarde zijn, of het nu een retourwaarde of refout parameter is.

Daarnaast is voor het gebruik out of ref de parameters vereist dat de bewerking een onderliggend antwoordbericht heeft om het gewijzigde object terug te dragen. Als uw bewerking eenrichtingsbewerking is, wordt er tijdens runtime een InvalidOperationException uitzondering gegenereerd.

Berichtbeveiligingsniveau voor het contract opgeven

Bij het ontwerpen van uw contract moet u ook het niveau voor berichtbeveiliging bepalen van services die uw contract implementeren. Dit is alleen nodig als berichtbeveiliging wordt toegepast op de binding in het eindpunt van het contract. Als de binding beveiliging heeft uitgeschakeld (dat wil zeggen, als de door het systeem geleverde binding de System.ServiceModel.SecurityMode waarde SecurityMode.Noneinstelt), hoeft u niet te beslissen over het beveiligingsniveau van het bericht voor het contract. In de meeste gevallen bieden door het systeem geleverde bindingen waarop beveiliging op berichtniveau is toegepast, een voldoende beveiligingsniveau en hoeft u niet het beveiligingsniveau voor elke bewerking of voor elk bericht te overwegen.

Het beveiligingsniveau is een waarde die aangeeft of de berichten (of berichtonderdelen) die ondersteuning bieden voor een service, worden ondertekend, ondertekend en versleuteld of zonder handtekeningen of versleuteling worden verzonden. Het beveiligingsniveau kan worden ingesteld op verschillende bereiken: op serviceniveau, voor een bepaalde bewerking, voor een bericht binnen die bewerking of een berichtonderdeel. Waarden die in één bereik zijn ingesteld, worden de standaardwaarde voor kleinere bereiken, tenzij deze expliciet worden overschreven. Als een bindingsconfiguratie het vereiste minimale beveiligingsniveau voor het contract niet kan bieden, wordt er een uitzondering gegenereerd. En wanneer er geen waarden voor beveiligingsniveau expliciet zijn ingesteld op het contract, bepaalt de bindingsconfiguratie het beveiligingsniveau voor alle berichten als de binding berichtbeveiliging heeft. Dit is het standaardgedrag.

Belangrijk

Bepalen of u expliciet verschillende bereiken van een contract wilt instellen op minder dan het volledige beveiligingsniveau, ProtectionLevel.EncryptAndSign is over het algemeen een beslissing die enige mate van beveiliging voor betere prestaties verhandelt. In deze gevallen moeten uw beslissingen betrekking hebben op uw bewerkingen en de waarde van de gegevens die ze uitwisselen. Zie Services beveiligen voor meer informatie.

In het volgende codevoorbeeld wordt bijvoorbeeld de ProtectionLevel eigenschap of eigenschap ProtectionLevel van het contract niet ingesteld.

[ServiceContract]  
public interface ISampleService  
{  
  [OperationContractAttribute]  
  public string GetString();  
  
  [OperationContractAttribute]  
  public int GetInt();
}  

Hier volgt de equivalente Visual Basic-code.

<ServiceContractAttribute()> _  
Public Interface ISampleService  
  
  <OperationContractAttribute()> _  
  Public Function GetString()As String  
  
  <OperationContractAttribute()> _  
  Public Function GetData() As Integer  
  
End Interface  

Wanneer u communiceert met een implementatie in een ISampleService eindpunt met een standaardwaarde WSHttpBinding (de standaardwaarde System.ServiceModel.SecurityMode, dat wil Messagewel), worden alle berichten versleuteld en ondertekend omdat dit het standaardbeveiligingsniveau is. Wanneer een ISampleService service echter wordt gebruikt met een standaardwaarde BasicHttpBinding (de standaardwaarde SecurityMode, dat wil Nonegezegd), worden alle berichten als tekst verzonden omdat er geen beveiliging is voor deze binding en dus wordt het beveiligingsniveau genegeerd (dat wil gezegd: de berichten worden niet versleuteld of ondertekend). Als het is SecurityMode gewijzigd in Message, worden deze berichten versleuteld en ondertekend (omdat dat nu het standaardbeveiligingsniveau van de binding zou zijn).

Als u expliciet de beveiligingsvereisten voor uw contract wilt opgeven of aanpassen, stelt u de ProtectionLevel eigenschap (of een van de ProtectionLevel eigenschappen in een kleiner bereik) in op het niveau dat uw servicecontract nodig heeft. In dit geval vereist het gebruik van een expliciete instelling de binding om die instelling ten minste te ondersteunen voor het gebruikte bereik. In het volgende codevoorbeeld wordt bijvoorbeeld expliciet één ProtectionLevel waarde opgegeven voor de GetGuid bewerking.

[ServiceContract]  
public interface IExplicitProtectionLevelSampleService  
{  
  [OperationContractAttribute]  
  public string GetString();  
  
  [OperationContractAttribute(ProtectionLevel=ProtectionLevel.None)]  
  public int GetInt();
  [OperationContractAttribute(ProtectionLevel=ProtectionLevel.EncryptAndSign)]  
  public int GetGuid();
}  

Hier volgt de equivalente Visual Basic-code.

<ServiceContract()> _
Public Interface IExplicitProtectionLevelSampleService
    <OperationContract()> _
    Public Function GetString() As String
    End Function
  
    <OperationContract(ProtectionLevel := ProtectionLevel.None)> _
    Public Function GetInt() As Integer
    End Function
  
    <OperationContractAttribute(ProtectionLevel := ProtectionLevel.EncryptAndSign)> _
    Public Function GetGuid() As Integer
    End Function
  
End Interface  

Een service die dit IExplicitProtectionLevelSampleService contract implementeert en een eindpunt heeft dat gebruikmaakt van de standaardwaarde WSHttpBinding (de standaardwaarde System.ServiceModel.SecurityMode, dat wil Messagezeggen) heeft het volgende gedrag:

  • De GetString bewerkingsberichten worden versleuteld en ondertekend.

  • De GetInt bewerkingsberichten worden verzonden als niet-versleutelde en niet-ondertekende tekst (dat wil wel zonder opmaak).

  • De GetGuid bewerking System.Guid wordt geretourneerd in een bericht dat is versleuteld en ondertekend.

Zie Understanding Protection Level (Beveiligingsniveau) voor meer informatie over beveiligingsniveaus en hoe u deze kunt gebruiken. Zie Services beveiligen voor meer informatie over beveiliging.

Overige vereisten voor bewerkingshandtekening

Voor sommige toepassingsfuncties is een bepaald type bewerkingshandtekening vereist. De NetMsmqBinding binding ondersteunt bijvoorbeeld duurzame services en clients, waarbij een toepassing tijdens de communicatie opnieuw kan worden opgestart en kan worden opgehaald waar deze was gebleven zonder berichten te missen. (Zie voor meer informatie Wachtrijen in WCF.) Duurzame bewerkingen moeten echter slechts één in parameter hebben en geen retourwaarde hebben.

Een ander voorbeeld is het gebruik van Stream typen in bewerkingen. Omdat de Stream parameter de volledige berichttekst bevat, moet het de enige invoer of uitvoer zijn die is opgegeven in de bewerking als invoer of uitvoer (dat wil gezegd parameter ref , out parameter of retourwaarde) van het type Streamzijn. Daarnaast moet de parameter of het retourtype zijn Stream, System.ServiceModel.Channels.Messageof System.Xml.Serialization.IXmlSerializable. Zie Large Data en Streaming voor meer informatie over streams.

Namen, naamruimten en verdoofing

De namen en naamruimten van de .NET-typen in de definitie van contracten en bewerkingen zijn aanzienlijk wanneer contracten worden geconverteerd naar WSDL en wanneer contractberichten worden gemaakt en verzonden. Daarom wordt het sterk aanbevolen dat servicecontractnamen en naamruimten expliciet worden ingesteld met behulp van de Name en Namespace eigenschappen van alle ondersteunende contractkenmerken zoals de ServiceContractAttribute, OperationContractAttribute, DataContractAttribute, en DataMemberAttributeandere contractkenmerken.

Een resultaat hiervan is dat als de namen en naamruimten niet expliciet zijn ingesteld, het gebruik van IL-verdoofing op de assembly de namen en naamruimten van het contract wijzigt en resulteert in gewijzigde WSDL- en wire-uitwisselingen die doorgaans mislukken. Als u de contractnamen en naamruimten niet expliciet instelt, maar wel van plan bent om verborgenheid te gebruiken, gebruikt u de ObfuscationAttribute en ObfuscateAssemblyAttribute kenmerken om te voorkomen dat de namen en naamruimten van het contracttype worden gewijzigd.

Zie ook