Programação no nível do canal de serviço
Este tópico descreve como escrever um aplicativo de serviço WCF (Windows Communication Foundation) sem usar o System.ServiceModel.ServiceHost e seu modelo de objeto associado.
Receber mensagens
Para estar pronto para receber e processar mensagens, as seguintes etapas são necessárias:
Crie uma ligação.
Crie um ouvinte de canal.
Abra o ouvinte do canal.
Leia o pedido e envie uma resposta.
Feche todos os objetos de canal.
Criando uma vinculação
O primeiro passo para ouvir e receber mensagens é criar uma ligação. O WCF é fornecido com várias ligações internas ou fornecidas pelo sistema que podem ser usadas diretamente instanciando uma delas. Além disso, você também pode criar sua própria vinculação personalizada instanciando uma classe CustomBinding, que é o que o código na listagem 1 faz.
O exemplo de código abaixo cria uma instância de e adiciona um System.ServiceModel.Channels.HttpTransportBindingElement à sua coleção Elements, que é uma coleção de elementos de ligação que são usados para criar a pilha de System.ServiceModel.Channels.CustomBinding canais. Neste exemplo, como a coleção de elementos tem apenas o HttpTransportBindingElement, a pilha de canais resultante tem apenas o canal de transporte HTTP.
Criando um ChannelListener
Depois de criar uma ligação, chamamos Binding.BuildChannelListener para construir o ouvinte de canal onde o parâmetro type é a forma de canal a ser criada. Neste exemplo, estamos usando System.ServiceModel.Channels.IReplyChannel porque queremos ouvir as mensagens recebidas em um padrão de troca de mensagens de solicitação/resposta.
IReplyChannel é usado para receber mensagens de solicitação e enviar mensagens de resposta. A chamada IReplyChannel.ReceiveRequest retorna um System.ServiceModel.Channels.IRequestChannelarquivo , que pode ser usado para receber a mensagem de solicitação e enviar de volta uma mensagem de resposta.
Ao criar o ouvinte, passamos o endereço de rede em que ele escuta, neste caso http://localhost:8080/channelapp
. Em geral, cada canal de transporte suporta um ou possivelmente vários esquemas de endereço, por exemplo, o transporte HTTP suporta esquemas http e https.
Também passamos um vazio System.ServiceModel.Channels.BindingParameterCollection ao criar o ouvinte. Um parâmetro binding é um mecanismo para passar parâmetros que controlam como o ouvinte deve ser construído. No nosso exemplo, não estamos usando nenhum desses parâmetros, então passamos uma coleção vazia.
Escutando mensagens recebidas
Em seguida, chamamos ICommunicationObject.Open o ouvinte e começamos a aceitar canais. O comportamento do IChannelListener<TChannel>.AcceptChannel depende se o transporte é orientado para conexão ou sem conexão. Para transportes orientados a conexão, AcceptChannel bloqueia até que uma nova solicitação de conexão chegue, momento em que retorna um novo canal que representa essa nova conexão. Para transportes sem conexão, como HTTP, AcceptChannel retorna imediatamente com o único canal que o ouvinte de transporte cria.
Neste exemplo, o ouvinte retorna um canal que implementa IReplyChannelo . Para receber mensagens neste canal, primeiro pedimos ICommunicationObject.Open que ele o coloque em um estado pronto para comunicação. Em seguida, ligamos ReceiveRequest para quais blocos até que uma mensagem chegue.
Ler o pedido e enviar uma resposta
Quando ReceiveRequest retorna um RequestContext, recebemos a mensagem recebida usando sua RequestMessage propriedade. Escrevemos a ação e o conteúdo do corpo da mensagem (que assumimos ser uma cadeia de caracteres).
Para enviar uma resposta, criamos uma nova mensagem de resposta, neste caso, repassando os dados da cadeia de caracteres que recebemos na solicitação. Em seguida, ligamos Reply para enviar a mensagem de resposta.
Fechando objetos
Para evitar vazamentos de recursos, é muito importante fechar objetos usados em comunicações quando eles não são mais necessários. Neste exemplo, fechamos a mensagem de solicitação, o contexto da solicitação, o canal e o ouvinte.
O exemplo de código a seguir mostra um serviço básico no qual um ouvinte de canal recebe apenas uma mensagem. Um serviço real continua aceitando canais e recebendo mensagens até que o serviço saia.
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