Condividi tramite


Programmazione del servizio Channel-Level

In questo argomento viene descritto come scrivere un'applicazione di servizio Windows Communication Foundation (WCF) senza utilizzare il System.ServiceModel.ServiceHost e il modello a oggetti ad esso associato.

Ricezione di messaggi

Per essere pronti a ricevere ed elaborare i messaggi, sono necessari i passaggi seguenti:

  1. Creare un legame.

  2. Costruire un listener di canale.

  3. Aprire il listener del canale.

  4. Leggere la richiesta e inviare una risposta.

  5. Chiudere tutti gli oggetti del canale.

Creazione di un collegamento

Il primo passaggio per l'ascolto e la ricezione di messaggi consiste nel creare un binding. WCF viene fornito con diversi collegamenti predefiniti o forniti dal sistema che possono essere utilizzati direttamente istanziando uno di essi. Inoltre, si può anche creare un'associazione personalizzata istanziando la classe CustomBinding, come mostrato nel codice dell'elenco 1.

L'esempio di codice seguente crea un'istanza di System.ServiceModel.Channels.CustomBinding e aggiunge un oggetto System.ServiceModel.Channels.HttpTransportBindingElement alla raccolta Elements, ovvero una raccolta di elementi di associazione utilizzati per compilare lo stack di canali. In questo esempio, poiché la raccolta di elementi ha solo HttpTransportBindingElement, lo stack di canali risultante ha solo il canale di trasporto HTTP.

Creazione di un ChannelListener

Dopo aver creato un'associazione, chiamiamo Binding.BuildChannelListener per costruire il listener del canale in cui il parametro di tipo è la forma del canale da creare. In questo esempio viene usato System.ServiceModel.Channels.IReplyChannel perché si vuole ascoltare i messaggi in arrivo in un modello di scambio di messaggi di richiesta/risposta.

IReplyChannel viene usato per ricevere messaggi di richiesta e inviare messaggi di risposta. La chiamata IReplyChannel.ReceiveRequest restituisce un System.ServiceModel.Channels.IRequestChannel, che può essere usato per ricevere il messaggio di richiesta e per inviare un messaggio di risposta.

Quando si crea il listener, si passa l'indirizzo di rete in cui è in ascolto, in questo caso http://localhost:8080/channelapp. In generale, ogni canale di trasporto supporta uno o più schemi di indirizzi, ad esempio, il trasporto HTTP supporta sia schemi http che https.

Viene inoltre passato un oggetto vuoto System.ServiceModel.Channels.BindingParameterCollection durante la creazione del listener. Un parametro di associazione è un meccanismo per passare parametri che controllano la modalità di compilazione del listener. In questo esempio non vengono usati parametri di questo tipo, quindi viene passata una raccolta vuota.

Ascolto dei messaggi in arrivo

Chiamiamo quindi ICommunicationObject.Open sull'ascoltatore e iniziamo ad accettare i canali. Il comportamento di IChannelListener<TChannel>.AcceptChannel dipende dal fatto che il trasporto sia orientato alla connessione o non orientato alla connessione. Per i trasporti orientati alla connessione, AcceptChannel blocca fino a quando non arriva una nuova richiesta di connessione a quel punto restituisce un nuovo canale che rappresenta la nuova connessione. Per i trasporti senza connessione, ad esempio HTTP, AcceptChannel restituisce immediatamente l'unico canale creato dal listener di trasporto.

In questo esempio il listener restituisce un canale che implementa IReplyChannel. Per ricevere messaggi su questo canale, si chiama prima ICommunicationObject.Open su esso per metterlo in uno stato pronto per la comunicazione. Chiamiamo quindi ReceiveRequest in modo che si blocchi fino all'arrivo di un messaggio.

Lettura della richiesta e invio di una risposta

Quando ReceiveRequest restituisce un RequestContextoggetto , viene visualizzato il messaggio ricevuto usando la relativa RequestMessage proprietà . Scriviamo il contenuto dell'azione e del corpo del messaggio( che si presuppone sia una stringa).

Per inviare una risposta, viene creato un nuovo messaggio di risposta in questo caso passando i dati stringa ricevuti nella richiesta. Viene quindi chiamato Reply per inviare il messaggio di risposta.

Chiusura di oggetti

Per evitare perdite di risorse, è molto importante chiudere gli oggetti usati nelle comunicazioni quando non sono più necessari. In questo esempio si chiude il messaggio di richiesta, il contesto della richiesta, il canale e il listener.

Nell'esempio di codice seguente viene illustrato un servizio di base in cui un listener del canale riceve un solo messaggio. Un vero servizio continua ad accettare canali e ricevere messaggi fino a quando il servizio non viene chiuso.

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: {message.Headers.Action}");
    string data=message.GetBody<string>();
    Console.WriteLine($"Message content: {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