Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Cette rubrique décrit les contrats de service, comment ils sont définis, quelles opérations sont disponibles (et les implications pour les échanges de messages sous-jacents), quels types de données sont utilisés et d’autres problèmes qui vous aident à concevoir des opérations qui répondent aux exigences de votre scénario.
Création d’un contrat de service
Les services exposent un certain nombre d'opérations. Dans les applications Windows Communication Foundation (WCF), définissez les opérations en créant une méthode et en la marquant avec l’attribut OperationContractAttribute . Ensuite, pour créer un contrat de service, regroupez vos opérations, soit en les déclarant dans une interface marquée avec l’attribut ServiceContractAttribute , soit en les définissant dans une classe marquée avec le même attribut. (Pour obtenir un exemple de base, consultez Guide pratique pour définir un contrat de service.)
Toutes les méthodes qui n’ont pas d’attribut OperationContractAttribute ne sont pas des opérations de service et ne sont pas exposées par les services WCF.
Cette rubrique décrit les points de décision suivants lors de la conception d’un contrat de service :
Indique s’il faut utiliser des classes ou des interfaces.
Comment spécifier les types de données que vous souhaitez échanger.
Types de modèles d’échange que vous pouvez utiliser.
Que vous puissiez inclure des exigences explicites de sécurité dans le contrat.
Restrictions relatives aux entrées et sorties des opérations.
Classes ou interfaces
Les deux classes et interfaces représentent un regroupement de fonctionnalités et, par conséquent, ils peuvent être utilisés pour définir un contrat de service WCF. Toutefois, il est recommandé d’utiliser des interfaces, car elles modélisent directement des contrats de service. Sans implémentation, les interfaces ne définissent pas plus qu’un regroupement de méthodes avec certaines signatures. Implémentez une interface de contrat de service et vous avez implémenté un service WCF.
Tous les avantages des interfaces managées s’appliquent aux interfaces de contrat de service :
Les interfaces de contrat de service peuvent étendre n’importe quel nombre d’autres interfaces de contrat de service.
Une classe unique peut implémenter n’importe quel nombre de contrats de service en implémentant ces interfaces de contrat de service.
Vous pouvez modifier l’implémentation d’un contrat de service en modifiant l’implémentation de l’interface, tandis que le contrat de service reste le même.
Vous pouvez versionr votre service en implémentant l’ancienne interface et la nouvelle. Les anciens clients se connectent à la version d’origine, tandis que les clients plus récents peuvent se connecter à la version la plus récente.
Remarque
Lorsque vous héritez d’autres interfaces de contrat de service, vous ne pouvez pas remplacer les propriétés d’opération, telles que le nom ou l’espace de noms. Si vous tentez de le faire, vous créez une opération dans le contrat de service actuel.
Pour obtenir un exemple d’utilisation d’une interface pour créer un contrat de service, consultez Comment : créer un service avec une interface de contrat.
Toutefois, vous pouvez utiliser une classe pour définir un contrat de service et implémenter ce contrat en même temps. L’avantage de créer vos services en appliquant ServiceContractAttribute et OperationContractAttribute directement à la classe et aux méthodes de la classe, respectivement, est la vitesse et la simplicité. Les inconvénients sont que les classes managées ne prennent pas en charge plusieurs héritages et, par conséquent, elles ne peuvent implémenter qu’un seul contrat de service à la fois. En outre, toute modification apportée aux signatures de classe ou de méthode modifie le contrat public pour ce service, ce qui peut empêcher les clients non modifiés d’utiliser votre service. Pour plus d’informations, consultez Implémentation de contrats de service.
Pour obtenir un exemple qui utilise une classe pour créer un contrat de service et l’implémente en même temps, consultez How to : Create a Service with a Contract Class.
À ce stade, vous devez comprendre la différence entre la définition de votre contrat de service à l’aide d’une interface et l’utilisation d’une classe. L’étape suivante consiste à décider quelles données peuvent être transmises entre un service et ses clients.
Paramètres et valeurs de retour
Chaque opération a une valeur de retour et un paramètre, même si ceux-ci sont void. Toutefois, contrairement à une méthode locale, dans laquelle vous pouvez passer des références à des objets d’un objet à un autre, les opérations de service ne passent pas de références à des objets. Au lieu de cela, elles passent des copies des objets.
Cela est significatif, car chaque type utilisé dans un paramètre ou une valeur de retour doit être sérialisable ; autrement dit, il doit être possible de convertir un objet de ce type en un flux d’octets et d’un flux d’octets en un objet.
Les types primitifs sont sérialisables par défaut, comme ce sont de nombreux types dans le .NET Framework.
Remarque
La valeur des noms de paramètres dans la signature de l'opération fait partie du contrat et respecte la casse. Si vous souhaitez utiliser le même nom de paramètre localement, mais modifier le nom dans les métadonnées publiées, consultez le System.ServiceModel.MessageParameterAttributefichier .
Contrats de données
Les applications orientées service comme les applications Windows Communication Foundation (WCF) sont conçues pour interagir avec le plus grand nombre possible d’applications clientes sur les plateformes Microsoft et non-Microsoft. Pour une interopérabilité la plus large possible, il est recommandé de marquer vos types avec les attributs DataContractAttribute et DataMemberAttribute pour créer un contrat de données, qui est la partie du contrat de service décrivant les données échangées par vos opérations de service.
Les contrats de données sont des contrats de style opt-in : aucun type ou membre de données n’est sérialisé, sauf si vous appliquez explicitement l’attribut de contrat de données. Les contrats de données ne sont pas liés à l’étendue d’accès du code managé : les membres de données privés peuvent être sérialisés et envoyés ailleurs pour être accessibles publiquement. (Pour obtenir un exemple de base d’un contrat de données, consultez Guide pratique pour créer un contrat de données de base pour une classe ou une structure.) WCF gère la définition des messages SOAP sous-jacents qui activent les fonctionnalités de l’opération, ainsi que la sérialisation de vos types de données dans et hors du corps des messages. Tant que vos types de données sont sérialisables, vous n’avez pas besoin de réfléchir à l’infrastructure d’échange de messages sous-jacente lors de la conception de vos opérations.
Bien que l’application WCF classique utilise les attributs DataContractAttribute et DataMemberAttribute pour créer des contrats de données pour les opérations, vous pouvez utiliser d’autres mécanismes de sérialisation. Les mécanismes ISerializable, SerializableAttribute et IXmlSerializable fonctionnent tous pour gérer la sérialisation de vos types de données dans les messages SOAP sous-jacents qui les transportent d’une application à une autre. Vous pouvez utiliser davantage de stratégies de sérialisation si vos types de données nécessitent une prise en charge spéciale. Pour plus d’informations sur les choix de sérialisation des types de données dans les applications WCF, consultez Spécification du transfert de données dans les contrats de service.
Mappage des paramètres et des valeurs de retour aux échanges de messages
Les opérations de service sont prises en charge par un échange sous-jacent de messages SOAP qui transfèrent les données d’application de nouveau et de retour, en plus des données requises par l’application pour prendre en charge certaines fonctionnalités de sécurité, de transaction et de session standard. Comme c’est le cas, la signature d’une opération de service détermine un certain modèle d’échange de messages sous-jacent (MEP) qui peut prendre en charge le transfert de données et les fonctionnalités requises par une opération. Vous pouvez spécifier trois modèles dans le modèle de programmation WCF : les modèles de requête/réponse, unidirectionnel et de message duplex.
Demande/réponse
Un modèle de demande/réponse est un modèle dans lequel un expéditeur de demande (une application cliente) reçoit une réponse avec laquelle la demande est corrélée. Il s’agit du MEP par défaut, car il prend en charge une opération dans laquelle un ou plusieurs paramètres sont passés à l’opération et qu'une valeur de retour est renvoyée à l’appelant. Par exemple, l’exemple de code C# suivant montre une opération de service de base qui prend une chaîne et retourne une chaîne.
[OperationContractAttribute]
string Hello(string greeting);
Voici le code Visual Basic équivalent.
<OperationContractAttribute()>
Function Hello (ByVal greeting As String) As String
Cette signature d’opération détermine la forme de l’échange de messages sous-jacent. Si aucune corrélation n’existait, WCF ne peut pas déterminer pour quelle opération la valeur de retour est prévue.
Notez que, sauf si vous spécifiez un modèle de message sous-jacent différent, même les opérations de service qui retournent void (Nothing en Visual Basic) sont des échanges de messages de demande/réponse. Le résultat de votre opération est que, sauf si un client appelle l’opération de façon asynchrone, le client cesse de traiter jusqu’à ce que le message de retour soit reçu, même si ce message est vide dans le cas normal. L’exemple de code C# suivant montre une opération qui ne retourne pas tant que le client n’a pas reçu un message vide en réponse.
[OperationContractAttribute]
void Hello(string greeting);
Voici le code Visual Basic équivalent.
<OperationContractAttribute()>
Sub Hello (ByVal greeting As String)
L’exemple précédent peut ralentir les performances et la réactivité des clients si l’opération prend beaucoup de temps, mais il existe des avantages pour les opérations de demande/réponse même lorsqu’elles retournent void. Le plus évident est que les erreurs SOAP peuvent être retournées dans le message de réponse, ce qui indique que certaines conditions d’erreur liées au service se sont produites, qu’elles soient en communication ou en traitement. Les erreurs SOAP spécifiées dans un contrat de service sont transmises à l’application cliente en tant qu’objet FaultException<TDetail> , où le paramètre de type est le type spécifié dans le contrat de service. Cela facilite la notification des clients sur les conditions d’erreur dans les services WCF. Pour plus d’informations sur les exceptions, les erreurs SOAP et la gestion des erreurs, consultez Spécification et gestion des erreurs dans les contrats et services. Pour voir un exemple de service de demande/réponse et de client, consultez Comment : créer un contrat Request-Reply. Pour plus d’informations sur les problèmes liés au modèle de demande-réponse, consultez Request-Reply Services.
Contrat unidirectionnel
Si le client d’une application de service WCF ne doit pas attendre que l’opération se termine et ne traite pas les erreurs SOAP, l’opération peut spécifier un modèle de message unidirectionnel. Une opération unidirectionnelle est une opération dans laquelle un client appelle une opération et continue de traiter une fois que WCF écrit le message sur le réseau. En règle générale, cela signifie que, sauf si les données envoyées dans le message sortant sont extrêmement volumineuses, le client continue à s’exécuter presque immédiatement (sauf s’il existe une erreur lors de l’envoi des données). Ce type de modèle d’échange de messages prend en charge le comportement de type événement d’un client à une application de service.
Un échange de messages dans lequel un message est envoyé et aucun message n’est reçu ne peut pas prendre en charge une opération de service qui spécifie une valeur de retour autre que void; dans ce cas, une InvalidOperationException exception est levée.
L'absence de message de retour signifie également qu'il ne peut y avoir aucune erreur SOAP retournée pour signaler une erreur lors du traitement ou de la communication. (La communication d’informations sur les erreurs lorsque les opérations sont des opérations unidirectionnelles nécessite un modèle d’échange de messages duplex.)
Pour spécifier un échange de messages unidirectionnel pour une opération qui retourne void, déterminez la propriété IsOneWay sur true, comme montré dans l’exemple de code C# suivant.
[OperationContractAttribute(IsOneWay=true)]
void Hello(string greeting);
Voici le code Visual Basic équivalent.
<OperationContractAttribute(IsOneWay := True)>
Sub Hello (ByVal greeting As String)
Cette méthode est identique à l’exemple de requête/réponse précédent, mais la définition de la IsOneWay propriété true signifie que bien que la méthode soit identique, l’opération de service n’envoie pas de message de retour et les clients retournent immédiatement une fois le message sortant remis à la couche de canal. Pour obtenir un exemple, consultez How to : Create a One-Way Contract. Pour plus d’informations sur le modèle unidirectionnel, consultez One-Way Services.
Duplex
Un modèle duplex est caractérisé par la capacité du service et du client à envoyer des messages entre eux indépendamment, qu’ils utilisent une messagerie unidirectionnelle ou demande/réponse. Cette forme de communication bidirectionnelle est utile pour les services qui doivent communiquer directement avec le client ou pour fournir une expérience asynchrone à l’un des deux côtés d’un échange de messages, y compris le comportement similaire à l’événement.
Le modèle duplex est légèrement plus complexe que les modèles de requête/réponse ou unidirectionnel en raison du mécanisme supplémentaire de communication avec le client.
Pour concevoir un contrat duplex, vous devez également concevoir un contrat de rappel et affecter le type de ce contrat de rappel à la CallbackContract propriété de l’attribut ServiceContractAttribute qui marque votre contrat de service.
Pour implémenter un modèle duplex, vous devez créer une deuxième interface qui contient les déclarations de méthode appelées sur le client.
Pour obtenir un exemple de création d’un service et d’un client qui accède à ce service, consultez How to : Create a Duplex Contract and How to : Access Services with a Duplex Contract. Pour obtenir un exemple de travail, consultez Duplex. Pour plus d’informations sur les problèmes liés à l’utilisation de contrats duplex, consultez Services Duplex.
Avertissement
Lorsqu’un service reçoit un message duplex, il examine l’élément ReplyTo de ce message entrant pour déterminer où envoyer la réponse. Si le canal utilisé pour recevoir le message n’est pas sécurisé, un client non approuvé peut envoyer un message malveillant avec un ordinateur ReplyTocible, ce qui entraîne un déni de service (DOS) de cet ordinateur cible.
Paramètres Out et Ref
Dans la plupart des cas, vous pouvez utiliser les paramètres in (ByVal en Visual Basic) et les paramètres out, ref (ByRef en Visual Basic). Étant donné que les deux out et ref les paramètres indiquent que les données sont retournées à partir d’une opération, une signature d’opération telle que la suivante spécifie qu’une opération de demande/réponse est requise même si la signature de l’opération retourne void.
[ServiceContractAttribute]
public interface IMyContract
{
[OperationContractAttribute]
public void PopulateData(ref CustomDataType data);
}
Voici le code Visual Basic équivalent.
<ServiceContractAttribute()> _
Public Interface IMyContract
<OperationContractAttribute()> _
Public Sub PopulateData(ByRef data As CustomDataType)
End Interface
Les seules exceptions sont les cas dans lesquels votre signature a une structure particulière. Par exemple, vous pouvez utiliser la NetMsmqBinding liaison pour communiquer avec les clients uniquement si la méthode utilisée pour déclarer une opération retourne void; il ne peut y avoir aucune valeur de sortie, qu’il s’agisse d’une valeur de retour, refou out d’un paramètre.
En outre, l’utilisation des paramètres out ou ref nécessite que l’opération ait un message de réponse sous-jacent permettant de renvoyer l’objet modifié. Si votre opération est une opération unidirectionnelle, une InvalidOperationException exception est levée à l'exécution.
Spécifier le niveau de protection des messages sur le contrat
Lors de la conception de votre contrat, vous devez également décider du niveau de protection des messages des services qui implémentent votre contrat. Cela est nécessaire uniquement si la sécurité de message est appliquée à la liaison dans le point de terminaison du contrat. Si la liaison a la sécurité désactivée (autrement dit, si la liaison fournie par le système définit System.ServiceModel.SecurityMode à la valeur SecurityMode.None), alors vous n’avez pas besoin de décider du niveau de protection des messages pour le contrat. Dans la plupart des cas, les liaisons fournies par le système avec la sécurité au niveau du message fournissent un niveau de protection suffisant et vous n’avez pas à prendre en compte le niveau de protection pour chaque opération ou pour chaque message.
Le niveau de protection est une valeur qui spécifie si les messages (ou parties de messages) qui prennent en charge un service sont signés, signés et chiffrés, ou envoyés sans signatures ni chiffrement. Le niveau de protection peut être défini à différentes étendues : au niveau du service, pour une opération particulière, pour un message au sein de cette opération ou une partie de message. Les valeurs définies à une étendue deviennent la valeur par défaut pour les étendues plus petites, sauf si elles sont remplacées explicitement. Si une configuration de liaison est incapable de fournir le niveau de protection minimum requis pour le contrat, une exception est levée. Et lorsqu’aucune valeur de niveau de protection n’est définie explicitement sur le contrat, la configuration de liaison contrôle le niveau de protection pour tous les messages si la liaison a une sécurité de message. Il s’agit du comportement par défaut.
Importante
Décider s’il faut définir explicitement différentes étendues d’un contrat à un niveau de protection inférieur au niveau de protection complet de ProtectionLevel.EncryptAndSign est généralement une décision qui échange un certain degré de sécurité pour améliorer les performances. Dans ces cas, vos décisions doivent tourner autour de vos opérations et de la valeur des données qu’ils échangent. Pour plus d’informations, consultez Sécurisation des services.
Par exemple, l'exemple de code suivant ne définit ni la propriété ProtectionLevel ni la propriété ProtectionLevel sur le contrat.
[ServiceContract]
public interface ISampleService
{
[OperationContractAttribute]
public string GetString();
[OperationContractAttribute]
public int GetInt();
}
Voici le code Visual Basic équivalent.
<ServiceContractAttribute()> _
Public Interface ISampleService
<OperationContractAttribute()> _
Public Function GetString()As String
<OperationContractAttribute()> _
Public Function GetData() As Integer
End Interface
Lors de l’interaction avec une ISampleService implémentation dans un point de terminaison avec un WSHttpBinding par défaut (le System.ServiceModel.SecurityMode par défaut, qui est Message), tous les messages sont chiffrés et signés, car il s’agit du niveau de protection par défaut. Toutefois, lorsqu'un ISampleService service est utilisé avec une liaison par défaut BasicHttpBinding (la liaison par défaut SecurityMode, qui est None), tous les messages sont envoyés en tant que texte, car il n'existe aucune sécurité pour cette liaison et donc le niveau de protection est ignoré (autrement dit, les messages ne sont ni chiffrés ni signés). Si la SecurityMode était remplacée par Message, ces messages seraient chiffrés et signés (car cela serait maintenant le niveau de protection par défaut de la liaison).
Si vous souhaitez spécifier ou ajuster explicitement les exigences de protection pour votre contrat, définissez la ProtectionLevel propriété (ou l’une des ProtectionLevel propriétés dans une plus petite étendue) au niveau requis par votre contrat de service. Dans ce cas, l’utilisation d’un paramètre explicite nécessite que la liaison prend en charge ce paramètre au minimum pour l’étendue utilisée. Par exemple, l’exemple de code suivant spécifie explicitement une ProtectionLevel valeur pour l’opération GetGuid .
[ServiceContract]
public interface IExplicitProtectionLevelSampleService
{
[OperationContractAttribute]
public string GetString();
[OperationContractAttribute(ProtectionLevel=ProtectionLevel.None)]
public int GetInt();
[OperationContractAttribute(ProtectionLevel=ProtectionLevel.EncryptAndSign)]
public int GetGuid();
}
Voici le code Visual Basic équivalent.
<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
Un service qui implémente ce contrat IExplicitProtectionLevelSampleService et possède un point de terminaison qui utilise la valeur par défaut de WSHttpBinding (System.ServiceModel.SecurityMode, qui est Message) présente le comportement suivant :
Les
GetStringmessages d’opération sont chiffrés et signés.Les
GetIntmessages d’opération sont envoyés sous forme de texte non chiffré et non signé (autrement dit, brut).L’opération
GetGuidSystem.Guid est retournée dans un message chiffré et signé.
Pour plus d’informations sur les niveaux de protection et leur utilisation, consultez Présentation du niveau de protection. Pour plus d’informations sur la sécurité, consultez Sécurisation des services.
Autres exigences de signature d’opération
Certaines fonctionnalités d’application nécessitent une signature d’opération particulière. Par exemple, la liaison NetMsmqBinding prend en charge les services et clients fiables, dans lesquels une application peut redémarrer au milieu de la communication et reprendre là où elle s’est interrompue sans entraîner la perte de messages. (Pour plus d’informations, consultez Files d’attente dans WCF.) Toutefois, les opérations durables ne doivent prendre qu’un in seul paramètre et n’ont aucune valeur de retour.
Un autre exemple est l’utilisation de Stream types dans les opérations. Étant donné que le Stream paramètre inclut l’intégralité du corps du message, si une entrée ou une sortie (autrement dit, ref paramètre, out paramètre ou valeur de retour) est de type Stream, il doit s’agir de la seule entrée ou sortie spécifiée dans votre opération. En outre, le type de paramètre ou de retour doit être soit Stream, System.ServiceModel.Channels.Messageou System.Xml.Serialization.IXmlSerializable. Pour plus d’informations sur les flux, consultez Données volumineuses et diffusion en continu.
Noms, espaces de noms et obscurcissement
Les noms et espaces de noms des types .NET dans la définition des contrats et des opérations sont significatifs lorsque les contrats sont convertis en WSDL et lorsque les messages de contrat sont créés et envoyés. Par conséquent, il est fortement recommandé que les noms et les espaces de noms de contrat de service soient définis explicitement à l’aide des propriétés Name et Namespace de tous les attributs de contrat de prise en charge, tels que les attributs de contrat ServiceContractAttribute, OperationContractAttribute, DataContractAttribute, DataMemberAttribute et d’autres attributs de contrat.
Il en résulte notamment que si les noms et les espaces de noms ne sont pas définis explicitement, l’utilisation de l’obfuscation IL sur l’assembly altère les noms et les espaces de noms des types de contrat, WSDL est modifié et les échanges sur le câble échouent généralement. Si vous ne définissez pas explicitement les noms des contrats et les espaces de noms mais que vous envisagez d’utiliser l’obfuscation, utilisez les attributs ObfuscationAttribute et ObfuscateAssemblyAttribute pour empêcher la modification des noms de type de contrat et des espaces de noms.
Voir aussi
- Guide pratique pour créer un contrat Request-Reply
- Guide pratique pour créer un contrat One-Way
- Guide pratique pour créer un contrat Duplex
- Spécification du transfert de données dans les contrats de service
- Spécification et gestion des erreurs dans les contrats et les services
- Utilisation de sessions
- Opérations synchrones et asynchrones
- Services fiables (Reliable Services)
- Services et transactions