Sink e catene di sink

Questo argomento è specifico di una tecnologia legacy mantenuta per una questione di compatibilità con le applicazioni esistenti di versioni precedenti e non è consigliato per il nuovo sviluppo. Le applicazioni distribuite devono ora essere sviluppate utilizzando  Windows Communication Foundation (WCF).

I client effettuano chiamate ai metodi sugli oggetti remoti inviando messaggi al dominio dell'applicazione remota. Ciò viene portato a termine da un set di oggetti canale. Il dominio dell'applicazione client contiene un canale client e il dominio dell'applicazione remota contiene un canale remoto. Ogni canale è composto di una serie di sink di canale collegati insieme in una catena. Nell'illustrazione seguente è mostrata la struttura di una catena di sink di canale di base.

Sink e catene di sink

Prima dell'invio o dopo la ricezione di un messaggio, i canali inviano ciascun messaggio lungo una catena di oggetti sink di canale. La catena di sink contiene sink necessari per le funzionalità di base del canale, quali sink del formattatore, di trasporto o del generatore di stack, ma è possibile personalizzare la catena di sink di canale per l'esecuzione di attività speciali con un messaggio o un flusso. Ogni sink di canale implementa IClientChannelSink o IServerChannelSinkfrlrfSystemRuntimeRemotingChannelsIServerChannelSinkClassTopic. Il primo sink di canale sul client deve implementare anche IMessageSinkfrlrfSystemRuntimeRemotingMessagingIMessageSinkClassTopic. Questo sink implementa in genere IClientFormatterSink (che eredita sia da IMessageSink, IChannelSinkBase che da IClientChannelSink) e viene chiamato sink del formattatore perché trasforma il messaggio in arrivo in un flusso (un oggetto IMessagefrlrfSystemRuntimeRemotingMessagingIMessageClassTopic).

La catena di sink di canale elabora qualsiasi messaggio inviato a o da un dominio di applicazione. Un sink di canale ha accesso al messaggio elaborato e l'elaborazione successiva utilizza il messaggio restituito al sistema dopo averlo elaborato. Si tratta del momento più adatto per implementare un servizio di registrazione o un qualsiasi tipo di filtro.

Ogni sink di canale elabora il flusso e quindi passa il flusso al prossimo sink di canale. Ciò vuol dire che i sink precedenti o successivi a uno specifico sink devono sapere come gestire il flusso ricevuto.

tdzwhfy3.note(it-it,VS.100).gifNota:
I sink di messaggio non devono generare eccezioni. Un sink dei messaggi può controllare questa operazione eseguendo il wrapping di codice del metodo in blocchi try/catch.

I provider di sink di canale (oggetti che implementano l'interfaccia IClientChannelSinkProviderfrlrfSystemRuntimeRemotingChannelsIClientChannelSinkProviderClassTopic, IClientFormatterSinkProviderfrlrfSystemRuntimeRemotingChannelsIClientFormatterSinkProviderClassTopic o IServerChannelSinkProvider) sono responsabili per la creazione dei sink di canale che elaborano messaggi .NET Remoting. Quando un tipo remoto viene attivato, il provider di sink di canale viene recuperato dal canale e viene chiamato il metodo CreateSink sul provider di sink per recuperare il primo sink di canale dalla catena.

I sink di canale sono responsabili del trasporto dei messaggi tra il client e il server. I sink di canale sono inoltre collegati tra loro in una catena. Quando il metodo CreateSink viene chiamato su un provider di sink, deve eseguire le operazioni seguenti:

  • Creare un sink di canale.

  • Chiamare CreateSink sul provider di sink del canale successivo.

  • Assicurare che il sink successivo e il corrente siano collegati tra loro.

  • Restituisce il suo sink al chiamante.

I sink di canale sono responsabili dell'inoltro di tutte le chiamate effettuate su di loro verso il sink successivo nella catena e devono fornire un meccanismo per l'archiviazione di un riferimento al sink successivo.

I sink di canale hanno una grande flessibilità nel decidere cosa inviare lungo la catena di sink. Ad esempio, sink di sicurezza che negoziano l'autenticazione prima di inviare il messaggio originale serializzato possono basarsi sul messaggio di canale completo, sostituire il flusso di contenuto con il proprio contenuto e inviarlo lungo la catena di sink e sul dominio dell'applicazione remota. Nel percorso di ritorno, il sink di sicurezza può intercettare il messaggio di risposta, creando una conversazione con i sink di sicurezza corrispondenti nel dominio dell'applicazione remota. Una volta che è stato raggiunto un accordo, il sink di sicurezza originario può inviare il flusso di contenuto originale sul dominio dell'applicazione remota.

Elaborazione di messaggi in catene di sink di canale

Una volta che il sistema .NET Remoting trova un canale in grado di elaborare il messaggio, il canale passa il messaggio al sink di canale del formattatore chiamando

SyncProcessMessage (o AsyncProcessMessage). Il sink del formattatore crea la matrice delle intestazioni di trasporto e chiama il metodo GetRequestStream sul sink successivo. La chiamata viene inoltrata lungo la catena di sink e qualsiasi sink può creare un flusso di richiesta che verrà passato nuovamente al sink del formattatore. Se GetRequestStream restituisce un riferimento null (Nothing in Visual Basic), il sink del formattatore crea un sink da utilizzare per la serializzazione. Al ritorno della chiamata, il messaggio viene serializzato e il metodo di elaborazione del messaggio appropriato viene chiamato sul primo sink di canale nella catena di sink.

I sink non possono scrivere dati nel flusso ma possono leggere dal flusso o passare un nuovo flusso ove necessario. I sink possono inoltre aggiungere intestazioni alla matrice di intestazioni (se non hanno precedentemente chiamato GetRequestStream sul sink successivo) e unirsi allo stack di sink prima di inoltrare la chiamata al sink successivo. (Lo stack di sincronizzazione è utilizzato per consentire alle chiamate asincrone di richiamare il chiamante quando vengono completate.) Quando la chiamata raggiunge il sink di trasporto alla fine della catena, questo invia le intestazioni e il messaggio serializzato sul canale al server, dove l'intero processo verrà invertito. Il sink di trasporto (sul server) recupera le intestazioni e il messaggio serializzato dal lato server del flusso e li inoltra lungo la catena di sink fino al sink del formattatore. Il messaggio viene deserializzato dal sink del formattatore e inoltrato ai servizi .NET Remoting, dove il messaggio verrà trasformato in una chiamata al metodo e verrà richiamato sull'oggetto server.

Creazione di catene di sink di canale

Per creare un nuovo sink di canale è necessario implementare e configurare il sistema .NET Remoting per riconoscere un'implementazione IServerChannelSinkProvider o IClientChannelSinkProvider in grado di creare l'implementazione personalizzata IClientChannelSink o IServerChannelSink o recuperare il sink successivo nella catena. È possibile utilizzare la classe astratta BaseChannelSinkWithProperties per consentire l'implementazione di sink di canale personalizzati.

Compilazione di un provider di sink di canale

Le applicazioni possono fornire provider di sink di canale del server o del client come parametri nella costruzione di un canale. I provider di sink di canale devono essere memorizzati in una catena ed è responsabilità dello sviluppatore concatenare tutti i provider di sink di canale prima di passare quello più esterno al costruttore di canale. Il provider di sink di canale implementa una proprietà Next per questo scopo. Nell'esempio di codice seguente viene illustrato come creare un provider di sink di canale del client. Un esempio completo è disponibile nella sezione Esempio di .NET Remoting: provider di sink di canale.

private Function CreateDefaultClientProviderChain() As IClientChannelSinkProvider
   Dim chain As New FirstClientFormatterSinkProvider            
   Dim sink As IClientChannelSinkProvider
   sink = chain
   sink.Next = New SecondClientFormatterSinkProvider
   sink = sink.Next
   return chain
End Function 
private IClientChannelSinkProvider CreateDefaultClientProviderChain(){
   IClientChannelSinkProvider chain = new FirstClientFormatterSinkProvider();            
   IClientChannelSinkProvider sink = chain;
   sink.Next = new SecondClientFormatterSinkProvider();
   sink = sink.Next;
   return chain;
} 
tdzwhfy3.note(it-it,VS.100).gifNota:
Quando in un file di configurazione vengono forniti più provider di sink di canale, il sistema .NET Remoting ne effettua il concatenamento nell'ordine in cui si trovano nel file di configurazione. I provider del sink di canale vengono creati alla creazione del canale, durante la chiamata di Configure.

Sink del formattatore

I sink del formattatore serializzano il messaggio del canale nel flusso del messaggio come un oggetto che implementa IMessage. Alcune implementazioni di sink del formattatore utilizzano i tipi di formattatore forniti dal sistema (BinaryFormatterfrlrfSystemRuntimeSerializationFormattersBinaryBinaryFormatterClassTopic e SoapFormatterfrlrfSystemRuntimeSerializationFormattersSoapSoapFormatterClassTopic). Altre implementazioni trasformano il messaggio del canale nel flusso in altri modi.

La funzione del sink del formattatore consiste nel generare le intestazioni necessarie e nel serializzare il messaggio nel flusso. Dopo il sink del formattatore, il messaggio viene inoltrato a tutti i sink nella catena dei sink di canale tramite le chiamate SyncProcessMessage o AsyncProcessMessage. In questa fase il messaggio è già stato serializzato e non può essere modificato.

tdzwhfy3.note(it-it,VS.100).gifNota:
I sink che devono creare o modificare il messaggio devono essere collocati nella catena di sink prima del formattatore. A questo scopo è sufficiente implementare IClientFormatterSink, comunicando al sistema che dispone di un riferimento al sink del formattatore. È quindi possibile inserire il vero sink del formattatore più avanti nella catena di sink.

Nel percorso di ritorno il sink del formattatore trasforma di nuovo il flusso del messaggio nell'oggetto del messaggio del canale (messaggio restituito). Il primo sink di canale sul client deve implementare l'interfaccia IClientFormatterSink. Quando CreateSinkviene restituito al canale, viene eseguito il cast del riferimento restituito a un tipo IClientFormatterSinkper permettere la chiamata del metodo SyncProcessMessage. Si ricordi che IClientFormatterSink è derivato da IMessageSink. Se il cast non riesce, il sistema genera un'eccezione.

Sink di canale personalizzati

Sul client, sink di canale personalizzati vengono inseriti nella catena di oggetti tra il sink del formattatore e l'ultimo sink di trasporto. Inserire un sink di canale personalizzato nel canale del client o del server consente di elaborare IMessage in uno dei momenti seguenti:

  • Durante il processo che converte una chiamata rappresentata come messaggio in un flusso e la invia sulla rete.

  • Durante il processo che preleva un token dalla rete e lo invia all'ultimo sink di messaggi prima dell'oggetto remoto sul server o l'oggetto proxy (sul client).

Sink personalizzati possono leggere o scrivere dati (se la chiamata è in uscita o in ingresso) nel flusso e aggiungere informazioni aggiuntive alle intestazioni dove desiderato. In questa fase il messaggio è già stato serializzato dal formattatore e non può essere modificato. Quando la chiamata del messaggio viene inoltrata al sink di trasporto alla fine della catena, il sink di trasporto scrive le intestazioni sul flusso e inoltra il flusso al sink di trasporto sul server utilizzando il protocollo di trasporto stabilito dal canale.

Sink di trasporto

Il sink di trasporto è l'ultimo sink nella catena sul client e il primo sink nella catena sul server. Oltre a trasportare il messaggio serializzato, il sink di trasporto è anche responsabile dell'invio delle intestazioni al server e del recupero delle intestazioni e del flusso quando il server restituisce la chiamata. Questi sink sono incorporati nel canale e non possono essere estesi.

Sostituzione del formattatore predefinito

Dal momento che un canale è un meccanismo di rete astratto, è possibile configurare il sistema .NET Remoting per combinare un canale implementato dal sistema con un qualsiasi formattatore. È possibile compiere questa operazione utilizzando il costruttore di canale che impiega un'implementazione IDictionary di proprietà del canale, un formattatore sul server e un formattatore sul client. È inoltre possibile specificare il formattatore in un file di configurazione. Nell'esempio seguente il sistema di configurazione .NET Remoting crea un HttpChannel ma utilizza BinaryClientFormatterSink sul client.

<configuration>
   <system.runtime.remoting>
      <application>
         <channels>
            <channel ref="http">
               <clientProviders>
                  <formatter ref="binary"/>
               </clientProviders>
         <channels>
      </application>
   </system.runtime.remoting>
</configuration> 

Nel codice seguente viene eseguita la stessa operazione a livello di codice, presupponendo un tipo di interfaccia remoto IService che implementa GetServerString e GetServerTime:

Imports System
Imports System.Collections
Imports System.Runtime.Remoting
Imports System.Runtime.Remoting.Channels
Imports System.Runtime.Remoting.Channels.Http

Public Class ClientProcess
  <MTAThread()> _
  Public Shared Sub Main()
      
    ' Note that any name/value pairs of configuration attributes can be 
    ' placed in this dictionary (the configuration system calls this same 
    ' constructor).
    Dim properties As New Hashtable()
    properties("name") = "HttpBinary"
     
    ChannelServices.RegisterChannel(New HttpChannel(properties, New BinaryClientFormatterSinkProvider(), Nothing))
    ' The last parameter above (Nothing) is the server sink provider chain 
    ' to obtain the default behavior (which includes SOAP and 
    ' binary formatters on the server side).
    Dim service As IService = CType(Activator.GetObject(GetType(IService), "http://computer:8080/SAService"), IService)
      
    Console.WriteLine("Server string is: " + service.GetServerString())
    Console.WriteLine("Server time is: " + service.GetServerTime())
  End Sub
   
End Class 
using System;
using System.Collections;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;

public class ClientProcess{

  public static void Main(string[] Args){
        
    // Note that any name/value pairs of configuration attributes can be 
    // placed in this dictionary (the configuration system calls this 
    // same HttpChannel constructor).
    IDictionary properties = new Hashtable();
    properties["name"] = "HttpBinary";

    // The last parameter below is the server sink provider chain 
    // to obtain the default behavior (which includes SOAP and binary 
    // formatters) on the server side.
    ChannelServices.RegisterChannel(new HttpChannel(properties, new BinaryClientFormatterSinkProvider(), null));

    IService service = (IService)Activator.GetObject(typeof(IService),"http://computer:8080/SAService");
        
    Console.WriteLine("Server string is: " + service.GetServerString());
    Console.WriteLine("Server time is: " + service.GetServerTime());      
  }
}

Per un esempio completo di questa combinazione di canale e formattatore ospitata in Internet Information Services (IIS), vedere Esempio di .NET Remoting: hosting in Internet Information Services (IIS).

Per far sì che il client utilizzi un oggetto TcpChannel con l'oggetto SoapClientFormatterSinkfrlrfSystemRuntimeRemotingChannelsSoapClientFormatterSinkClassTopic, è necessario modificare solo gli spazi dei nomi e la chiamata RegisterChannel **** , come mostrato nel codice seguente:

ChannelServices.RegisterChannel(New TcpChannel(properties, New SoapClientFormatterSinkProvider(), Nothing))
ChannelServices.RegisterChannel(new TcpChannel(properties, new SoapClientFormatterSinkProvider(), null));

Vedere anche

Concetti

Hosting di oggetti remoti in Internet Information Services (IIS)
Esempio di .NET Remoting: hosting in Internet Information Services (IIS)

Altre risorse

.NET Remoting avanzato