Services monodirectionnels
Le comportement par défaut d'une opération de service est le modèle demande-réponse. Dans un modèle demande-réponse, le client attend le message de réponse, même si l'opération de service est représentée dans le code en tant que méthode void. Avec une opération monodirectionnelle, un seul message est transmis. Le récepteur n'envoie pas de message de réponse, l'expéditeur n'en attend pas.
Utilisez le modèle de design monodirectionnel :
- Lorsque le client doit appeler des opérations et n'est pas affecté par le résultat de l'opération au niveau de l'opération.
- Lorsque vous utilisez la classe NetMsmqBinding ou MsmqIntegrationBinding. (Pour plus d'informations sur ce scénario, consultez Files d'attente dans Windows Communication Foundation).
Lorsqu'une opération est monodirectionnelle, il n'y a pas de message pour renvoyer des informations sur l'erreur au client. Vous pouvez détecter des conditions d'erreur à l'aide de fonctionnalités de la liaison sous-jacente, telle que les sessions fiables, ou en concevant un contrat de service duplex qui utilise deux opérations monodirectionnelles : un contrat monodirectionnel du client au service afin d'appeler l'opération de service, et un autre contrat monodirectionnel entre le service et le client afin que le service puisse renvoyer des erreurs au client à l'aide d'un rappel que le client implémente.
Pour créer un contrat de service monodirectionnel, définissez votre contrat de service, appliquez la classe OperationContractAttribute à chaque opération et affectez true à la propriété IsOneWay, tel qu'indiqué dans l'exemple de code suivant.
[ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples")]
public interface IOneWayCalculator
{
[OperationContract(IsOneWay=true)]
void Add(double n1, double n2);
[OperationContract(IsOneWay = true)]
void Subtract(double n1, double n2);
[OperationContract(IsOneWay = true)]
void Multiply(double n1, double n2);
[OperationContract(IsOneWay = true)]
void Divide(double n1, double n2);
}
Pour obtenir un exemple complet, consultez l'exemple Service Contract: One-Way.
Blocage de clients à l'aide d'opérations monodirectionnelles
Il est important de se rendre compte qu'alors que certaines applications monodirectionnelles sont retournées dès que les données sortantes sont écrites dans la connexion réseau, l'implémentation d'une liaison ou d'un service peut, dans plusieurs scénarios, provoquer le blocage d'un client WCF à l'aide d'opérations monodirectionnelles. Dans les applications clientes WCF, l'objet client WCF ne retourne pas tant que les données sortantes ne sont pas écrites dans la connexion réseau. Cela se vérifie pour l'ensemble des modèles d'échange de messages, dont les opérations monodirectionnelles ; cela signifie que les problèmes d'écriture de données sur le transport empêchent le client de retourner. Selon le problème, le résultat peut être une exception ou un retard d'envoi des messages au service.
Par exemple, si le transport ne peut pas trouver le point de terminaison, une exception System.ServiceModel.EndpointNotFoundException est levée sans beaucoup de retard. Toutefois, il est également possible que le service ne puisse pas lire les données du câble pour une raison quelconque, ce qui empêche l'opération d'envoi du transport client de retourner. Dans ce cas, si le délai System.ServiceModel.Channels.Binding.SendTimeout sur la liaison de transport client est dépassé, une exception System.TimeoutException est levée, mais pas tant que le délai d'attente n'a pas été dépassé. Il est également possible qu'il y ait un nombre si élevé de messages sur un service que celui-ci ne puisse pas les traiter passé un certain stade. Dans ce cas également, le client monodirectionnel se bloque jusqu'à ce que le service puisse traiter les messages ou jusqu'à ce qu'une exception soit levée.
Une autre variante est le cas où la propriété de service System.ServiceModel.ServiceBehaviorAttribute.ConcurrencyMode a la valeur Single et la liaison utilise des sessions. Dans ce cas, le répartiteur applique un classement sur les messages entrants (spécification de sessions), ce qui empêche les messages suivants d'être lus sur le réseau tant que le service n'a pas traité le message précédent de cette session. À nouveau, le client se bloque, mais la survenue d'une exception repose sur la capacité du service à traiter les données en attente avant le dépassement du délai défini sur le client.
Vous pouvez limiter ce problème en insérant une mémoire tampon entre l'objet client et l'opération d'envoi du transport client. Par exemple, l'utilisation d'appels asynchrones ou d'une file d'attente de messages en mémoire permet à l'objet client de retourner rapidement. Ces deux approches peuvent augmenter la fonctionnalité, mais la taille du pool de threads et de la file d'attente de messages pose encore des limites.
Nous vous recommandons, à la place, d'examinez les divers contrôles sur le service ainsi que sur le client, puis de tester vos scénarios d'application afin de déterminer la meilleure configuration de part et d'autre. Par exemple, si l'utilisation de sessions bloque le traitement de messages sur votre service, vous pouvez affecter PerCall à la propriété System.ServiceModel.ServiceBehaviorAttribute.InstanceContextMode afin que chaque message puisse être traité par une instance de service différente, et affecter Multiple à ConcurrencyMode afin de permettre à plusieurs threads de distribuer des messages simultanément. Une autre approche consiste à augmenter les quotas de lecture du service et les liaisons clientes.