Not
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Det här avsnittet beskriver vad tjänstkontrakt är, hur de definieras, vilka åtgärder som är tillgängliga (och konsekvenserna för de underliggande meddelandeutbytena), vilka datatyper som används och andra problem som hjälper dig att utforma åtgärder som uppfyller kraven i ditt scenario.
Skapa ett tjänstkontrakt
Tjänster exponerar ett antal åtgärder. I WCF-program (Windows Communication Foundation) definierar du åtgärderna genom att skapa en metod och markera den med attributet OperationContractAttribute . Om du sedan vill skapa ett tjänstkontrakt grupperar du dina åtgärder, antingen genom att deklarera dem i ett gränssnitt som markerats med ServiceContractAttribute attributet eller genom att definiera dem i en klass som har markerats med samma attribut. (Ett grundläggande exempel finns i Så här definierar du ett tjänstkontrakt.)
Alla metoder som inte har ett OperationContractAttribute attribut är inte tjänståtgärder och exponeras inte av WCF-tjänster.
I det här avsnittet beskrivs följande beslutspunkter när du utformar ett tjänstkontrakt:
Om du vill använda klasser eller gränssnitt.
Så här anger du de datatyper som du vill utbyta.
De typer av utbytesmönster som du kan använda.
Om du kan göra explicita säkerhetskrav till en del av kontraktet.
Begränsningarna för operationens indata och utdata.
Klasser eller gränssnitt
Både klasser och gränssnitt representerar en gruppering av funktioner och därför kan båda användas för att definiera ett WCF-tjänstkontrakt. Vi rekommenderar dock att du använder gränssnitt eftersom de direkt modellerar tjänstkontrakt. Utan en implementering definierar gränssnitt bara en gruppering av metoder med vissa signaturer. Implementera ett tjänstkontraktsgränssnitt och du har implementerat en WCF-tjänst.
Alla fördelar med hanterade gränssnitt gäller för tjänstkontraktsgränssnitt:
Servicekontraktsgränssnitt kan utöka valfritt antal andra tjänstkontraktsgränssnitt.
En enda klass kan implementera valfritt antal tjänstkontrakt genom att implementera dessa tjänstkontraktsgränssnitt.
Du kan ändra implementeringen av ett tjänstkontrakt genom att ändra gränssnittsimplementeringen, medan tjänstkontraktet förblir detsamma.
Du kan version din tjänst genom att implementera det gamla gränssnittet och det nya. Gamla klienter ansluter till den ursprungliga versionen, medan nyare klienter kan ansluta till den nyare versionen.
Anmärkning
När du ärver från andra tjänstkontraktsgränssnitt kan du inte åsidosätta åtgärdsegenskaper, till exempel namn eller namnområde. Om du försöker göra det skapar du en ny åtgärd i det aktuella tjänstkontraktet.
Ett exempel på hur du använder ett gränssnitt för att skapa ett tjänstkontrakt finns i Så här skapar du en tjänst med ett kontraktsgränssnitt.
Du kan dock använda en klass för att definiera ett tjänstkontrakt och implementera det kontraktet samtidigt. Fördelen med att skapa dina tjänster genom att tillämpa ServiceContractAttribute och OperationContractAttribute direkt på klassen och metoderna i klassen är snabbhet och enkelhet. Nackdelarna är att hanterade klasser inte stöder flera arv, och därför kan de bara implementera ett tjänstkontrakt i taget. Dessutom ändrar alla ändringar av klass- eller metodsignaturerna det offentliga kontraktet för tjänsten, vilket kan förhindra att oförändrade klienter använder din tjänst. Mer information finns i Implementera tjänstkontrakt.
Ett exempel som använder en klass för att skapa ett tjänstkontrakt och implementerar det samtidigt finns i How to: Create a Service with a Contract Class (Så här skapar du en tjänst med en kontraktsklass).
Nu bör du förstå skillnaden mellan att definiera ditt tjänstkontrakt med hjälp av ett gränssnitt och genom att använda en klass. Nästa steg är att bestämma vilka data som kan skickas fram och tillbaka mellan en tjänst och dess klienter.
Parametrar och returvärden
Varje åtgärd har ett returvärde och en parameter, även om dessa är void. Men till skillnad från en lokal metod, där du kan skicka referenser till objekt från ett objekt till ett annat, skickar inte tjänståtgärder referenser till objekt. I stället skickar de kopior av objekten.
Detta är viktigt eftersom varje typ som används i en parameter eller ett returvärde måste vara serialiserbar. Det måste alltså vara möjligt att konvertera ett objekt av den typen till en ström med byte och från en ström med byte till ett objekt.
Primitiva typer kan serialiseras som standard, liksom många typer i .NET Framework.
Anmärkning
Värdena för parameternamnen i operationssignaturen är en del av kontraktet och är skiftlägeskänsliga. Om du vill använda samma parameternamn lokalt men ändra namnet i publicerade metadata, se System.ServiceModel.MessageParameterAttribute.
Datakontrakt
Tjänstorienterade program som WCF-program (Windows Communication Foundation) är utformade för att samverka med bredast möjliga antal klientprogram på både Microsoft- och icke-Microsoft-plattformar. För största möjliga samverkan rekommenderar vi att du markerar dina typer med attributen DataContractAttribute och DataMemberAttribute för att skapa ett datakontrakt, vilket är den del av tjänstkontraktet som beskriver de data som dina tjänståtgärder utbyter.
Datakontrakt är kontrakt av typen opt-in: Ingen typ eller datakomponent serialiseras om du inte uttryckligen tillämpar datakontraktsattributet. Datakontrakt är inte relaterade till åtkomstomfånget för den hanterade koden: Privata datamedlemmar kan serialiseras och skickas någon annanstans för att nås offentligt. (Ett grundläggande exempel på ett datakontrakt finns i Så här skapar du ett grundläggande datakontrakt för en klass eller struktur.) WCF hanterar definitionen av underliggande SOAP-meddelanden som aktiverar åtgärdens funktioner samt serialiseringen av dina datatyper till och från meddelandenas brödtext. Så länge dina datatyper är serialiserbara behöver du inte tänka på den underliggande infrastrukturen för meddelandeutbyte när du utformar dina åtgärder.
Även om det typiska WCF-programmet använder attributen DataContractAttribute och DataMemberAttribute för att skapa datakontrakt för åtgärder, kan du använda andra serialiseringsmekanismer. Standardmekanismerna ISerializable, SerializableAttributeoch IXmlSerializable fungerar alla för att hantera serialiseringen av dina datatyper i de underliggande SOAP-meddelandena som bär dem från ett program till ett annat. Du kan använda fler serialiseringsstrategier om dina datatyper kräver särskilt stöd. Mer information om alternativen för serialisering av datatyper i WCF-program finns i Ange dataöverföring i tjänstkontrakt.
Mappa parametrar och returnera värden till meddelandeutbyten
Tjänståtgärder stöds av ett underliggande utbyte av SOAP-meddelanden som överför programdata fram och tillbaka, utöver de data som krävs av programmet för att stödja vissa standardfunktioner för säkerhet, transaktioner och sessioner. Eftersom så är fallet dikterar signaturen för en tjänståtgärd ett visst underliggande mönster för meddelandeutbyte (MEP) som kan stödja dataöverföringen och de funktioner som en åtgärd kräver. Du kan ange tre mönster i WCF-programmeringsmodellen: mönster för begäran/svar, enkelriktade och duplexmeddelanden.
Begäran/svar
Ett mönster för begäran/svar är ett där en begärandesändare (ett klientprogram) tar emot ett svar som begäran är korrelerad med. Detta är standard-MEP eftersom det stöder en åtgärd där en eller flera parametrar skickas till åtgärden och ett returvärde skickas tillbaka till anroparen. I följande C#-kodexempel visas till exempel en grundläggande tjänståtgärd som tar en sträng och returnerar en sträng.
[OperationContractAttribute]
string Hello(string greeting);
Följande är motsvarande Visual Basic-kod.
<OperationContractAttribute()>
Function Hello (ByVal greeting As String) As String
Den här åtgärdssignaturen dikterar formen av underliggande meddelandeutbyte. Om det inte finns någon korrelation kan WCF inte avgöra för vilken åtgärd returvärdet är avsett för.
Observera att om du inte anger ett annat underliggande meddelandemönster är även tjänståtgärder som returnerar void (Nothing i Visual Basic) utbyten av begärande-/svarsmeddelanden. Resultatet för åtgärden är att om inte en klient anropar åtgärden asynkront slutar klienten bearbeta tills returmeddelandet tas emot, även om meddelandet är tomt i det normala fallet. Följande C#-kodexempel visar en åtgärd som inte returneras förrän klienten har fått ett tomt meddelande som svar.
[OperationContractAttribute]
void Hello(string greeting);
Följande är motsvarande Visual Basic-kod.
<OperationContractAttribute()>
Sub Hello (ByVal greeting As String)
Föregående exempel kan försämra klientens prestanda och svarstider om åtgärden tar lång tid att utföra, men det finns fördelar med begärande-/svarsåtgärder även när de returnerar void. Den mest uppenbara är att SOAP-fel kan returneras i svarsmeddelandet, vilket indikerar att något tjänstrelaterat feltillstånd har inträffat, oavsett om det är i kommunikation eller bearbetning. SOAP-fel som anges i ett tjänstkontrakt skickas till klientprogrammet som ett FaultException<TDetail> objekt, där typparametern är den typ som anges i tjänstkontraktet. Detta gör det enkelt att meddela klienter om feltillstånd i WCF-tjänster. Mer information om undantag, SOAP-fel och felhantering finns i Ange och hantera fel i Kontrakt och tjänster. Ett exempel på en begäran/svarstjänst och -klient finns i Så här skapar du ett Request-Reply kontrakt. Mer information om problem med mönstret för svar på begäran finns iRequest-Reply Services.
Enkelriktad
Om klienten för ett WCF-tjänstprogram inte ska vänta tills åtgärden har slutförts och inte bearbetar SOAP-fel kan åtgärden ange ett enkelriktad meddelandemönster. En enkelriktad åtgärd är en åtgärd där en klient anropar en åtgärd och fortsätter bearbetningen efter att WCF har skrivit meddelandet till nätverket. Detta innebär vanligtvis att om inte de data som skickas i det utgående meddelandet är extremt stora fortsätter klienten att köras nästan omedelbart (om det inte uppstår ett fel när data skickas). Den här typen av meddelandeutbytesmönster stöder händelseliknande beteende från en klient till ett tjänstprogram.
Ett meddelandeutbyte där ett meddelande skickas och inget tas emot kan inte stödja en tjänståtgärd som anger ett annat returvärde än void; i det här fallet utlöses ett InvalidOperationException undantag.
Inget returmeddelande innebär också att det inte kan finnas något SOAP-fel som returneras för att indikera eventuella fel i bearbetningen eller kommunikationen. (Kommunikation av felinformation när åtgärder är enkelriktade åtgärder kräver ett duplex-meddelandeutbytesmönster.)
Om du vill ange ett enkelriktat meddelandeutbyte för en åtgärd som returnerar void, anger du egenskapen IsOneWay till true, som i följande C#-kodexempel.
[OperationContractAttribute(IsOneWay=true)]
void Hello(string greeting);
Följande är motsvarande Visual Basic-kod.
<OperationContractAttribute(IsOneWay := True)>
Sub Hello (ByVal greeting As String)
Den här metoden är identisk med föregående exempel på begäran/svar, men om du anger IsOneWay egenskapen till true innebär det att även om metoden är identisk skickar inte tjänståtgärden ett returmeddelande och klienterna returnerar omedelbart när det utgående meddelandet har överlämnats till kanallagret. Ett exempel finns i How to: Create a One-Way Contract (Så här skapar du ett One-Way kontrakt). Mer information om enkelriktade mönster finns iOne-Way Services.
Duplex
Ett duplexmönster kännetecknas av både tjänstens och klientens förmåga att skicka meddelanden till varandra oberoende av om de använder enkelriktade meddelanden eller begärande-/svarsmeddelanden. Den här typen av dubbelriktad kommunikation är användbar för tjänster som måste kommunicera direkt till klienten eller för att tillhandahålla en asynkron upplevelse på båda sidor av ett meddelandeutbyte, inklusive händelseliknande beteende.
Duplex-mönstret är något mer komplext än mönster för begäran/svar eller enkelriktade mönster på grund av den ytterligare mekanismen för kommunikation med klienten.
Om du vill utforma ett duplexkontrakt måste du också utforma ett återanropskontrakt och tilldela typen av det återanropskontraktet till egenskapen för CallbackContract-attributet ServiceContractAttribute som markerar ditt tjänstekontrakt.
Om du vill implementera ett duplexmönster måste du skapa ett andra gränssnitt som innehåller de metoddeklarationer som anropas på klienten.
Ett exempel på hur du skapar en tjänst och en klient som har åtkomst till tjänsten finns i How to: Create a Duplex Contract and How to: Access Services with a Duplex Contract (Så här skapar du ett Duplex-kontrakt och Så här gör du för att: Få åtkomst till tjänster med ett Duplex-kontrakt). Ett arbetsexempel finns i Duplex. Mer information om problem med duplexkontrakt finns i Duplex Services.
Försiktighet
När en tjänst tar emot ett duplex-meddelande tittar den på elementet ReplyTo i det inkommande meddelandet för att avgöra var svaret ska skickas. Om den kanal som används för att ta emot meddelandet inte är skyddad kan en icke-betrodd klient skicka ett skadligt meddelande med måldatorns ReplyTo, vilket leder till doS (Denial of Service) för måldatorn.
Ut- och referensparametrar
I de flesta fall kan du använda in parametrar (ByVal i Visual Basic) och out parametrar ref (ByRef i Visual Basic). Eftersom både out och ref parametrar anger att data returneras från en åtgärd, anger en åtgärdssignatur, till exempel följande, att en begäran/svar-åtgärd krävs trots att åtgärdens signatur returnerar void.
[ServiceContractAttribute]
public interface IMyContract
{
[OperationContractAttribute]
public void PopulateData(ref CustomDataType data);
}
Följande är motsvarande Visual Basic-kod.
<ServiceContractAttribute()> _
Public Interface IMyContract
<OperationContractAttribute()> _
Public Sub PopulateData(ByRef data As CustomDataType)
End Interface
De enda undantagen är de fall där din signatur har en viss struktur. Du kan till exempel bara använda bindningen NetMsmqBinding för att kommunicera med klienter om metoden som används för att deklarera en åtgärd returnerar void. Det kan inte finnas något utdatavärde, oavsett om det är ett returvärde eller refout en parameter.
Dessutom kräver användning out eller ref parametrar att åtgärden har ett underliggande svarsmeddelande för att överföra det ändrade objektet. Om åtgärden är en enkelriktad åtgärd utlöses ett InvalidOperationException undantag vid körning.
Ange meddelandeskyddsnivå för kontraktet
När du utformar ditt kontrakt måste du också bestämma meddelandeskyddsnivån för tjänster som implementerar ditt kontrakt. Detta är bara nödvändigt om meddelandesäkerhet tillämpas på bindningen i kontraktets slutpunkt. Om bindningen har säkerhet inaktiverad (d.v.s. om den systembaserade bindningen anger System.ServiceModel.SecurityMode värdet SecurityMode.None) behöver du inte bestämma meddelandeskyddsnivån för kontraktet. I de flesta fall ger systembaserade bindningar med säkerhet på meddelandenivå en tillräcklig skyddsnivå och du behöver inte ta hänsyn till skyddsnivån för varje åtgärd eller för varje meddelande.
Skyddsnivån är ett värde som anger om de meddelanden (eller meddelandedelar) som stöder en tjänst signeras, signeras och krypteras eller skickas utan signaturer eller kryptering. Skyddsnivån kan anges på olika omfång: På tjänstnivå, för en viss åtgärd, för ett meddelande inom den åtgärden eller en meddelandedel. Värden som anges inom ett sammanhang blir standardvärden för mindre sammanhang, om de inte uttryckligen åsidosätts. Om en bindningskonfiguration inte kan tillhandahålla den lägsta skyddsnivå som krävs för kontraktet utlöses ett undantag. Och när inga skyddsnivåvärden uttryckligen anges i kontraktet styr bindningskonfigurationen skyddsnivån för alla meddelanden om bindningen har meddelandesäkerhet. Det här är standardbeteendet.
Viktigt!
Att besluta om att uttryckligen sätta olika omfattningar av ett kontrakt till mindre än den fullständiga skyddsnivån för ProtectionLevel.EncryptAndSign är vanligtvis ett beslut som byter en viss grad av säkerhet mot ökad prestanda. I dessa fall måste dina beslut kretsa kring dina åtgärder och värdet på de data som de utbyter. Mer information finns i Skydda tjänster.
I följande kodexempel anges till exempel inte antingen ProtectionLevel egenskapen eller ProtectionLevel för kontraktet.
[ServiceContract]
public interface ISampleService
{
[OperationContractAttribute]
public string GetString();
[OperationContractAttribute]
public int GetInt();
}
Följande är motsvarande Visual Basic-kod.
<ServiceContractAttribute()> _
Public Interface ISampleService
<OperationContractAttribute()> _
Public Function GetString()As String
<OperationContractAttribute()> _
Public Function GetData() As Integer
End Interface
När du interagerar med en ISampleService implementering i en slutpunkt med ett standardvärde WSHttpBinding (standardvärdet System.ServiceModel.SecurityMode, som är Message), krypteras och signeras alla meddelanden eftersom detta är standardskyddsnivån. Men när en ISampleService tjänst används med ett standardvärde BasicHttpBinding (standardvärdet SecurityMode, vilket är None), skickas alla meddelanden som text eftersom det inte finns någon säkerhet för den här bindningen och därför ignoreras skyddsnivån (det vill sägs att meddelandena varken är krypterade eller signerade). Om har SecurityMode ändrats till Messageskulle dessa meddelanden krypteras och signeras (eftersom det nu skulle vara bindningens standardskyddsnivå).
Om du uttryckligen vill ange eller justera skyddskraven för ditt kontrakt anger ProtectionLevel du egenskapen (eller någon av ProtectionLevel egenskaperna i ett mindre omfång) till den nivå som ditt tjänstkontrakt kräver. I det här fallet kräver användningen av en explicit inställning att bindningen åtminstone kan stödja den inställningen för det specificerade användningsområdet. I följande kodexempel anges till exempel ett ProtectionLevel värde explicit för åtgärden GetGuid .
[ServiceContract]
public interface IExplicitProtectionLevelSampleService
{
[OperationContractAttribute]
public string GetString();
[OperationContractAttribute(ProtectionLevel=ProtectionLevel.None)]
public int GetInt();
[OperationContractAttribute(ProtectionLevel=ProtectionLevel.EncryptAndSign)]
public int GetGuid();
}
Följande är motsvarande Visual Basic-kod.
<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
En tjänst som implementerar det här IExplicitProtectionLevelSampleService kontraktet och har en slutpunkt som använder standardvärdet WSHttpBinding (standardvärdet System.ServiceModel.SecurityMode, som är Message) har följande beteende:
Åtgärdsmeddelandena
GetStringkrypteras och signeras.Åtgärdsmeddelandena
GetIntskickas som okrypterad och osignerad (d.v.s. oformaterad) text.Åtgärden
GetGuidSystem.Guid returneras i ett meddelande som är krypterat och signerat.
Mer information om skyddsnivåer och hur du använder dem finns i Förstå skyddsnivå. Mer information om säkerhet finns i Skydda tjänster.
Krav för annan operationssignatur
Vissa programfunktioner kräver en viss typ av åtgärdssignatur. Bindningen NetMsmqBinding stöder till exempel varaktiga tjänster och klienter, där ett program kan startas om mitt i kommunikationen och fortsätta där den slutade utan att några meddelanden saknas. (Mer information finns i Köer i WCF.) Varaktiga åtgärder får dock bara ta en in parameter och har inget returvärde.
Ett annat exempel är användningen av Stream typer i åtgärder. Eftersom parametern Stream innehåller hela meddelandetexten, om indata eller utdata (dvs ref . parameter, out parameter eller returvärde) är av typen Streammåste det vara den enda indata eller utdata som angetts i åtgärden. Dessutom måste parametern eller returtypen vara antingen Stream, System.ServiceModel.Channels.Messageeller System.Xml.Serialization.IXmlSerializable. Mer information om strömmar finns i Stora data och strömning.
Namn, namnområden och obfuscation
Namnen och namnrymderna för .NET-typerna i definitionen av kontrakt och åtgärder är viktiga när kontrakt konverteras till WSDL och när kontraktmeddelanden skapas och skickas. Därför rekommenderar vi starkt att namn och namnrymder för tjänstkontrakt uttryckligen anges med hjälp av Name och Namespace egenskaperna för alla stödkontraktsattribut, till exempel attributen ServiceContractAttribute, OperationContractAttribute, DataContractAttribute, DataMemberAttribute och andra kontraktsattribut.
Ett resultat av detta är att om namnen och namnrymderna inte uttryckligen anges, ändrar användningen av IL-fördunkling på samlingen kontrakttypnamnen och namnrymderna, vilket resulterar i ändrade WSDL- och meddelandeutbyten som vanligtvis misslyckas. Om du inte uttryckligen anger kontraktnamnen och namnrymderna, men tänker använda fördunkling, använder du attributen ObfuscationAttribute och ObfuscateAssemblyAttribute för att förhindra att kontrakttypnamnen och namnrymderna ändras.