Programmation de service au niveau du canal
Cette rubrique explique comment écrire une application de service Windows Communication Foundation (WCF) sans utiliser System.ServiceModel.ServiceHost et son modèle objet associé.
réception de messages
Pour pouvoir recevoir et traiter des messages, vous devez effectuer les étapes suivantes :
Créer une liaison.
Générer un écouteur de canal.
Ouvrir l'écouteur de canal.
Lire la demande et envoyer une réponse.
Fermer tous les objets de canal.
Création d’une liaison
La première étape pour écouter et recevoir des messages consiste à créer une liaison. WCF est fourni avec plusieurs liaisons intégrées ou fournies par le système qui peuvent être utilisées directement ou par instanciation. Vous pouvez également créer votre propre liaison personnalisée en instanciant une classe CustomBinding, comme dans le code n°1.
L’exemple de code suivant crée une instance de System.ServiceModel.Channels.CustomBinding et ajoute un System.ServiceModel.Channels.HttpTransportBindingElement à sa collection Elements qui est une collection d’éléments de liaison utilisés pour générer la pile de canaux. Dans cet exemple, la collection d'éléments ayant uniquement le HttpTransportBindingElement, la pile de canaux résultante dispose uniquement du canal de transport HTTP.
Génération d'un ChannelListener
Après avoir créé une liaison, nous appelons Binding.BuildChannelListener pour générer l'écouteur de canal où le paramètre de type est la forme de canal à créer. Dans cet exemple, nous utilisons System.ServiceModel.Channels.IReplyChannel car nous souhaitons écouter les messages entrants dans un modèle d'échange de messages demande/réponse.
IReplyChannel est utilisé pour recevoir des messages de demande et renvoyer des messages de réponse. IReplyChannel.ReceiveRequest retourne un System.ServiceModel.Channels.IRequestChannel, qui peut être utilisé pour recevoir le message de demande et renvoyer un message de réponse.
Lors de la création de l'écouteur, nous passons l'adresse réseau sur laquelle il écoute, en l'occurrence http://localhost:8080/channelapp
. En général, chaque canal de transport prend en charge un ou plusieurs schémas d'adressage ; le transport HTTP, par exemple, prend en charge les schémas http et https.
Nous passons également un System.ServiceModel.Channels.BindingParameterCollection vide lors de la création de l'écouteur. Un paramètre de liaison est un mécanisme permettant de passer des paramètres qui contrôlent la manière dont l’écouteur doit être généré. Dans notre exemple, nous n’utilisons pas de tels paramètres ; nous passons donc une collection vide.
Écoute des messages entrants
Nous appelons ensuite ICommunicationObject.Open sur l'écouteur et nous commençons à accepter des canaux. Le comportement de IChannelListener<TChannel>.AcceptChannel varie selon que le transport est orienté connexion ou sans connexion. Pour les transports orientés connexion, AcceptChannel se bloque jusqu'à ce qu'une nouvelle demande de connexion arrive, auquel point il retourne un nouveau canal qui représente cette nouvelle connexion. Pour les transports sans connexion, tels que HTTP, AcceptChannel est retourné immédiatement avec l'unique canal que l'écouteur de transport crée.
Dans cet exemple, l'écouteur retourne un canal qui implémente IReplyChannel. Pour recevoir des messages sur ce canal, nous appelons d'abord ICommunicationObject.Open sur lui afin de le placer dans un état prêt pour la communication. Nous appelons ensuite ReceiveRequest, qui se bloque jusqu'à ce qu'un message arrive.
Lecture de la demande et envoi de la réponse
Lorsque ReceiveRequest retourne un RequestContext, nous obtenons le message reçu à l'aide de sa propriété RequestMessage. Nous écrivons l'action et le contenu du corps du message (que nous supposons être une chaîne).
Pour envoyer une réponse, nous créons un message de réponse ; en l'occurrence, nous repassons les données de chaîne que nous avons reçues dans la demande. Nous appelons ensuite Reply pour envoyer le message de réponse.
Fermeture des objets
Pour éviter toute fuite des ressources, il est très important de fermer les objets utilisés dans les communications lorsqu'ils ne sont plus nécessaires. Dans cet exemple, nous fermons le message de demande, le contexte de demande, le canal et l'écouteur.
L'exemple de code suivant illustre un service de base dans lequel un écouteur de canal reçoit un seul message. Un vrai service continue à accepter des canaux et à recevoir des messages jusqu'à ce que le service s'arrête.
using System;
using System.ServiceModel.Channels;
namespace ProgrammingChannels
{
class Service
{
static void RunService()
{
//Step1: Create a custom binding with just TCP.
BindingElement[] bindingElements = new BindingElement[2];
bindingElements[0] = new TextMessageEncodingBindingElement();
bindingElements[1] = new HttpTransportBindingElement();
CustomBinding binding = new CustomBinding(bindingElements);
//Step2: Use the binding to build the channel listener.
IChannelListener<IReplyChannel> listener =
binding.BuildChannelListener<IReplyChannel>(
new Uri("http://localhost:8080/channelapp"),
new BindingParameterCollection());
//Step3: Listening for messages.
listener.Open();
Console.WriteLine(
"Listening for incoming channel connections");
//Wait for and accept incoming connections.
IReplyChannel channel = listener.AcceptChannel();
Console.WriteLine("Channel accepted. Listening for messages");
//Open the accepted channel.
channel.Open();
//Wait for and receive a message from the channel.
RequestContext request= channel.ReceiveRequest();
//Step4: Reading the request message.
Message message = request.RequestMessage;
Console.WriteLine("Message received");
Console.WriteLine("Message action: {0}",
message.Headers.Action);
string data=message.GetBody<string>();
Console.WriteLine("Message content: {0}",data);
//Send a reply.
Message replymessage=Message.CreateMessage(
binding.MessageVersion,
"http://contoso.com/someotheraction",
data);
request.Reply(replymessage);
//Step5: Closing objects.
//Do not forget to close the message.
message.Close();
//Do not forget to close RequestContext.
request.Close();
//Do not forget to close channels.
channel.Close();
//Do not forget to close listeners.
listener.Close();
}
public static void Main()
{
Service.RunService();
Console.WriteLine("Press enter to exit");
Console.ReadLine();
}
}
}
Imports System.ServiceModel.Channels
Namespace ProgrammingChannels
Friend Class Service
Private Shared Sub RunService()
'Step1: Create a custom binding with just TCP.
Dim bindingElements(1) As BindingElement = {New TextMessageEncodingBindingElement(), _
New HttpTransportBindingElement()}
Dim binding As New CustomBinding(bindingElements)
'Step2: Use the binding to build the channel listener.
Dim listener = binding.BuildChannelListener(Of IReplyChannel)(New Uri("http://localhost:8080/channelapp"), _
New BindingParameterCollection())
'Step3: Listening for messages.
listener.Open()
Console.WriteLine("Listening for incoming channel connections")
'Wait for and accept incoming connections.
Dim channel = listener.AcceptChannel()
Console.WriteLine("Channel accepted. Listening for messages")
'Open the accepted channel.
channel.Open()
'Wait for and receive a message from the channel.
Dim request = channel.ReceiveRequest()
'Step4: Reading the request message.
Dim message = request.RequestMessage
Console.WriteLine("Message received")
Console.WriteLine("Message action: {0}", message.Headers.Action)
Dim data = message.GetBody(Of String)()
Console.WriteLine("Message content: {0}", data)
'Send a reply.
Dim replymessage = Message.CreateMessage(binding.MessageVersion, _
"http://contoso.com/someotheraction", data)
request.Reply(replymessage)
'Step5: Closing objects.
'Do not forget to close the message.
message.Close()
'Do not forget to close RequestContext.
request.Close()
'Do not forget to close channels.
channel.Close()
'Do not forget to close listeners.
listener.Close()
End Sub
Public Shared Sub Main()
Service.RunService()
Console.WriteLine("Press enter to exit")
Console.ReadLine()
End Sub
End Class
End Namespace