Condividi tramite


Programmazione client a livello di canale

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

Ricezione di messaggi

Per prepararsi alla ricezione e all'elaborazione di messaggi, è necessario eseguire i passaggi seguenti:

  1. Creare un'associazione.

  2. Generare un listener di canale.

  3. Aprire il listener del canale.

  4. Leggere la richiesta e inviare una risposta.

  5. Chiudere tutti gli oggetti canale.

Creazione di un'associazione

Il primo passaggio dell'attesa e della ricezione di messaggi consiste nel creare un'associazione. In WCF sono disponibili molte associazioni incorporate o fornite dal sistema che è possibile utilizzare direttamente creando un'istanza. È inoltre possibile creare un'associazione personalizzata creando un'istanza della classe CustomBinding, operazione che viene eseguita nel codice dell'elenco 1.

Nell'esempio di codice seguente viene creata un'istanza di System.ServiceModel.Channels.CustomBinding e viene aggiunto un elemento System.ServiceModel.Channels.HttpTransportBindingElement alla raccolta Elements, una raccolta di elementi di associazione utilizzati per generare lo stack di canali. Nell'esempio, poiché la raccolta degli elementi presenta solo HttpTransportBindingElement, lo stack di canali risultante dispone solo del canale di trasporto HTTP.

Generazione di un listener di canale.

Dopo avere creato un'associazione, si chiama il metodo System.ServiceModel.Channels.Binding.BuildChannelListener.Uri,System.ServiceModel.Channels.BindingParameterCollection) per generare il listener del canale in cui il parametro di tipo è il canale da creare. In questo esempio si utilizza System.ServiceModel.Channels.IReplyChannel perché si desidera ascoltare i messaggi in arrivo in un modello di scambio di messaggi Request/Reply.

IReplyChannel viene utilizzato per ricevere messaggi di richiesta e restituire messaggi di risposta. La chiamata a System.ServiceModel.Channels.IReplyChannel.ReceiveRequest restituisce un elemento System.ServiceModel.Channels.IRequestChannel, utilizzabile per ricevere il messaggio di richiesta e restituire un messaggio di risposta.

Quando si crea il listener, si passa l'indirizzo di rete su cui è in ascolto, in questo caso https://localhost:8080/channelapp. In genere, ogni canale del trasporto supporta uno o probabilmente più schemi di indirizzo, ad esempio il trasporto HTTP supporta entrambi gli schemi http e https.

Durante la creazione del listener si passa inoltre un elemento System.ServiceModel.Channels.BindingParameterCollection vuoto. Un parametro dell'associazione è un meccanismo che consente di passare parametri che controllano la modalità di generazione del listener. Poiché nell'esempio questi parametri non vengono utilizzati, viene passata una raccolta vuota.

Ascolto di messaggi in arrivo

Si passa quindi a chiamare System.ServiceModel.ICommunicationObject.Open sul listener e si inizia ad accettare canali. Il comportamento del metodo System.ServiceModel.Channels.IChannelListener.AcceptChannel dipende dalla natura del trasporto, orientato alla connessione o senza connessione. Per trasporti orientati alla connessione, AcceptChannel si blocca fino all'arrivo di una nuova richiesta di connessione, quindi restituisce un nuovo canale che rappresenta la nuova connessione. Per trasporti senza connessione, ad esempio HTTP, AcceptChannel restituisce immediatamente l'unico canale che il listener del trasporto crea.

Nell'esempio il listener restituisce un canale che implementa IReplyChannel. Per ricevere messaggi su questo canale si chiama prima System.ServiceModel.ICommunicationObject.Open sul canale per prepararlo alla comunicazione. Si chiama quindi ReceiveRequest che si blocca fino all'arrivo di un messaggio.

Lettura della richiesta e invio della risposta

Quando ReceiveRequest restituisce un elemento RequestContext, si ottiene il messaggio ricevuto utilizzando la proprietà RequestMessage. Si scrivono l'azione e il contenuto del corpo del messaggio (presumibilmente una stringa).

Per inviare una risposta, si crea un messaggio di risposta, ovvero in questo caso passando i dati di tipo stringa ricevuti nella richiesta. Si chiama quindi Reply per inviare il messaggio di risposta.

Chiusura di oggetti

Per evitare la perdita di risorse, è molto importante chiudere gli oggetti utilizzati nelle comunicazioni quando non sono più necessari. Nell'esempio si chiudono 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 solo uno messaggio. Un servizio reale continua ad accettare canali e a ricevere messaggi fino alla chiusura del servizio.

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("https://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, 
        "https://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();
}
}
}