Programación de servicios a nivel de canal
En este tema se describe cómo escribir una aplicación de servicio Windows Communication Foundation (WCF) sin usar System.ServiceModel.ServiceHost ni su modelo de objetos asociado.
recibir mensajes
Se exigen los pasos siguientes para estar listo para recibir y procesar mensajes:
Cree un enlace.
Crear una escucha del canal.
Abrir la escucha del canal.
Leer la solicitud y enviar una respuesta.
Cerrar todos los objetos de canal.
Crear un enlace
El primer paso para escuchar y recibir mensajes es crear un enlace. WCF se envía con varios enlaces que integra o proporciona el sistema y que se pueden usar directamente mediante la creación de instancias de uno de ellos. Además, también puede crear su propio enlace personalizado creando instancias de una clase CustomBinding que es lo que hace el código en la lista 1.
El ejemplo de código siguiente crea una instancia de System.ServiceModel.Channels.CustomBinding y agrega System.ServiceModel.Channels.HttpTransportBindingElement a su colección Elements, que es una colección de elementos de enlace que se utilizan para crear la pila del canal. En este ejemplo, puesto que la colección de elementos tiene solo HttpTransportBindingElement, la pila del canal resultante tiene solo el canal de transporte HTTP.
Crear un ChannelListener
Después de crear un enlace, llamamos a Binding.BuildChannelListener para crear la escucha del canal donde el parámetro de tipo es la forma del canal a crear. En este ejemplo estamos utilizando System.ServiceModel.Channels.IReplyChannel porque deseamos realizar escuchas para los mensajes entrantes en un patrón de intercambio de solicitud/mensaje de respuesta.
IReplyChannel se utiliza para recibir los mensajes de solicitud y devolver los mensajes de respuesta. Al llamar a IReplyChannel.ReceiveRequest, se devuelve System.ServiceModel.Channels.IRequestChannel, que se puede utilizar para recibir el mensaje de solicitud y devolver un mensaje de respuesta.
Al crear el agente de escucha, pasamos la dirección de red en la que se realizan las escuchas, en este caso http://localhost:8080/channelapp
. En general, cada canal de transporte admite uno o posiblemente varios esquemas de direcciones, por ejemplo, el transporte HTTP admite http y esquemas http.
También pasamos un System.ServiceModel.Channels.BindingParameterCollection vacío al crear el agente de escucha. Un parámetro de enlace es un mecanismo para pasar parámetros que controlan cómo el agente de escucha debe crearse. En nuestro ejemplo, no estamos utilizando ninguno de estos parámetros, por lo que pasamos una colección vacía.
Realizar escuchas para los mensajes entrantes
Llamamos a continuación ICommunicationObject.Open en el agente de escucha e iniciamos los canales de aceptación. El comportamiento de IChannelListener<TChannel>.AcceptChannel depende de si el transporte está orientado a la conexión o es sin conexión. Para los transportes orientados a la conexión, AcceptChannel se bloquea hasta que llega una nueva solicitud de conexión y, en ese momento, devuelve un nuevo canal que representa esa nueva conexión. Para los transportes sin conexión, como HTTP, AcceptChannel devuelve inmediatamente con el único el canal que el agente de escucha de transporte crea.
En este ejemplo, el agente de escucha devuelve un canal que implementa IReplyChannel. Para recibir mensajes en este canal, llamamos primero a ICommunicationObject.Open para colocarlo en un estado listo para la comunicación. Llamamos a continuación a ReceiveRequest que se bloquea hasta que llega un mensaje.
Leer la solicitud y enviar una respuesta
Cuando ReceiveRequest devuelve RequestContext, obtenemos el mensaje recibido mediante su propiedad RequestMessage. Eliminamos la acción del mensaje y el contenido del cuerpo (que suponemos es una cadena).
Para enviar una respuesta, creamos un nuevo mensaje de respuesta en este caso devolviendo los datos de cadena que recibimos en la solicitud. Llamamos a continuación a Reply para enviar el mensaje de respuesta.
Cerrar objetos
Para evitar agotar los recursos, es muy importante cerrar los objetos utilizados en comunicaciones cuando no ya se requieren. En este ejemplo cerramos el mensaje de solicitud, el contexto de solicitud, el canal y el agente de escucha.
El ejemplo de código siguiente muestra un servicio básico en el que un agente de escucha del canal recibe solo uno mensaje. Un servicio real sigue aceptando los canales y recibiendo los mensajes hasta que se abandone el servicio.
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