Partager via


Récepteurs et chaînes de récepteurs

Les canaux envoient chaque message avec une chaîne d'objets de récepteur de canaux avant l'envoi ou après la réception d'un message. Cette chaîne de récepteur contient des récepteurs nécessaires aux fonctionnalités de canal de base telles que les récepteurs de formateur, de transport ou de générateur de pile, cependant, vous pouvez personnaliser la chaîne de récepteurs de canal pour effectuer des tâches spéciales à l'aide d'un message ou d'un flux.

Chaque récepteur de canal implémente soit IClientChannelSink, soit IServerChannelSink. Le premier récepteur de canal côté client doit également implémenter IMessageSink. Il implémente généralement IClientFormatterSink (qui hérite de IMessageSink, IChannelSinkBase et IClientChannelSink) et il est appelé récepteur de formateur car il transforme le message entrant en un flux (un objet IMessage).

La chaîne de récepteurs de canal traite tout message qui est envoyé vers ou depuis un domaine d'application. Le message est tout ce dont vous disposez à ce moment-là, mais vous pouvez effectuer n'importe quelle opération avec ce message, et les traitements ultérieurs utiliseront ce message que vous retournez au système après traitement. C'est l'endroit idéal pour implémenter un service d'enregistrement, n'importe quel type de filtre ou peut-être du cryptage ou d'autres mesures de sécurité sur le client ou le serveur. L'illustration suivante montre la structure d'une chaîne de récepteurs de canal de base.

Chaîne de récepteurs de canal de base

Remarquez que chaque récepteur de canal traite le flux puis le passe au récepteur de canal suivant, ce qui signifie que les objets situés avant ou après votre récepteur doivent savoir comment traiter le flux que vous leur avez passé.

Remarque   Les récepteurs de message ne doivent pas lever d'exceptions. L'une des façons pour un récepteur de message de contrôler cela est d'envelopper du code de méthode dans des blocs try-catch.

Les fournisseurs de récepteur de canal (objets qui implémentent les interfaces IClientChannelSinkProvider, IClientFormatterSinkProvider ou IServerChannelSinkProvider) sont conçus pour créer les récepteurs de canal par l'intermédiaire desquels passe le flux des messages d'accès distant. Lorsqu'un type distant est activé, le fournisseur de récepteur de canal est extrait du canal ; la méthode CreateSink est appelée sur le fournisseur de récepteur pour extraire le premier canal dans le récepteur à partir de la chaîne.

Les récepteurs de canal sont chargés de transporter les messages entre le client et le serveur. Les récepteurs de canal sont également liés pour former une chaîne. Lorsque la méthode CreateSink est appelée sur un fournisseur de récepteur, il doit effectuer les tâches suivantes :

  • Créer son propre récepteur de canal.
  • Appeler CreateSink sur le fournisseur de récepteur suivant dans la chaîne.
  • Garantir que le récepteur suivant et celui en cours sont liés ensemble.
  • Retourner son récepteur à l'appelant.

Les récepteurs de canal sont chargés de transmettre tous les appels effectués sur eux au récepteur suivant dans la chaîne et doivent fournir un mécanisme de stockage d'une référence vers le récepteur suivant.

Les récepteurs de canal possèdent une grande flexibilité par rapport au contenu qu'ils envoient à la chaîne de récepteurs. Par exemple, les récepteurs de sécurité qui veulent négocier une authentification avant d'envoyer le véritable message sérialisé d'origine peuvent conserver le message de canal complet, remplacer le flux de contenu par leur propre contenu, et l'envoyer dans la chaîne de récepteur et au domaine d'application distant. Lors du retour, le récepteur de sécurité peut intercepter le message de réponse en créant une conversation avec les récepteurs de sécurité correspondant dans le domaine d'application distant. Une fois qu'il y a accord, le récepteur de sécurité d'origine peut envoyer le flux de contenu d'origine au domaine d'application distant.

Traitement de message dans la chaîne de récepteurs de canal

Une fois que le système .NET Remoting localise un canal qui peut traiter l'implémentation de IMethodCallMessage, le canal passe le message au récepteur de canal de formateur en appelant IMessageSink.SyncProcessMessage (ou IMessageSink.AsyncProcessMessage). Le récepteur de formateur crée le tableau d'en-tête de transport et appelle IClientChannelSink.GetRequestStream sur le récepteur suivant. Cet appel est transféré dans la chaîne de récepteurs et tout récepteur peut créer un flux de demande qui sera repassé au récepteur de formateur. Si GetRequestStream retourne une référence null (Nothing dans Visual Basic), le récepteur de formateur crée son propre récepteur à des fins de sérialisation. Au retour de cet appel, le message est sérialisé et la méthode appropriée de traitement du message est appelée sur le premier récepteur de canal dans la chaîne de récepteurs.

Les récepteurs ne peuvent pas écrire de données dans le flux mais peuvent lire le flux ou passer un nouveau flux là ou c'est nécessaire. Les récepteurs peuvent également ajouter des en-têtes au tableau d'en-tête (s'ils n'ont pas appelé auparavant GetRequestStream sur le récepteur suivant) et peuvent s'ajouter eux-mêmes à la pile de récepteurs avant de transmettre l'appel au récepteur suivant. Lorsque l'appel parvient au récepteur de transport au bout de la chaîne, le récepteur de transport envoie les en-têtes et le message sérialisé sur le canal au serveur où l'intégralité du processus est inversé. Le récepteur de transport (côté serveur) extrait les en-têtes et le message sérialisé à partir du côté serveur du flux et les transfère par l'intermédiaire de la chaîne de récepteurs jusqu'à ce qu'ils parviennent au récepteur de formateur. Le récepteur de formateur désérialise le message et le transmet au système d'accès distant où le message est renvoyé dans un appel de méthode et est appelé sur l'objet serveur.

Création de chaînes de récepteurs de canal

Pour créer un nouveau récepteur de canal, vous devez implémenter et configurer le système d'accès distant pour reconnaître une implémentation IServerChannelSinkProvider ou IClientChannelSinkProvider qui peut créer votre implémentation IClientChannelSink ou IServerChannelSink personnalisée ou extraire le récepteur suivant de la chaîne. Vous pouvez utiliser la classe abstraite BaseChannelSinkWithProperties afin de permettre l'implémentation de vos récepteurs de canal personnalisés.

Création d'un fournisseur de récepteur de canal

Les applications peuvent fournir des fournisseurs de récepteur de canal client ou serveur sous la forme de paramètres lors de la construction d'un canal. Les fournisseurs de récepteur de canal doivent être stockés dans une chaîne, et l'utilisateur a la responsabilité du chaînage de tous les fournisseurs de récepteur de canal entre eux avant de passer le fournisseur externe au constructeur de canal. Le fournisseur de récepteur de canal implémente une propriété Next à cet effet. L'exemple de code suivant montre comment créer un fournisseur de récepteur de canal côté client. Un exemple complet est disponible à Exemple d'accès distant : fournisseur de récepteur de canal.

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 
[C#]
private IClientChannelSinkProvider CreateDefaultClientProviderChain(){
   IClientChannelSinkProvider chain = new FirstClientFormatterSinkProvider();            
   IClientChannelSinkProvider sink = chain;
   sink.Next = new SecondClientFormatterSinkProvider();
   sink = sink.Next;
   return chain;
} 

Remarque   Quand plusieurs fournisseurs de récepteur de canal sont fournis dans un fichier de configuration, le système d'accès distant enchaîne ceux-ci les uns aux autres dans l'ordre dans lequel ils sont trouvés dans le fichier de configuration. Les fournisseurs de récepteur de canal sont créés lorsque le canal est créé lors de l'appel de RemotingConfiguration.Configure.

Récepteurs de formateur

Les récepteurs de formateur sérialisent le message de canal dans le flux de message comme un objet qui implémente IMessage. Certaines implémentations de récepteur de formateur utilisent les types de formateurs fournis par le système (BinaryFormatter et SoapFormatter). Les autres implémentations peuvent utiliser leurs propres moyens pour transformer le message de canal en flux.

La fonction du récepteur de formateur consiste à générer les en-têtes nécessaires et à sérialiser le message dans le flux. Après le récepteur de formateur, le message est transmis à tous les récepteurs dans la chaîne de récepteurs de canal à l'aide d'appels à IMessageSink.ProcessMessage ou IMessageSink.AsyncProcessMessage. À cette étape, le message a déjà été sérialisé et est fourni à titre d'information uniquement.

**Remarque   **Les récepteurs qui ont besoin de créer ou de modifier le message lui-même doivent être placés dans la chaîne de récepteurs avant le formateur. Cette opération s'effectue facilement en implémentant IClientFormatterSink ce qui fait croire au système qu'il possède une référence vers le récepteur de formateur. Le récepteur de formateur peut alors être placé ultérieurement dans la chaîne de récepteurs.

Lors du retour, le récepteur de formateur reconvertit le flux de message en éléments de message de canal (message de retour). Le premier récepteur de canal côté client doit également implémenter l'interface IClientFormatterSink. Lorsque CreateSink retourne le canal, la référence retournée est castée en type IClientFormatterSink de façon à ce que SyncProcessMessage de l'interface IMessage puisse être appelé. En cas d'échec du cast, le système lève une exception.

Récepteurs de canal personnalisés

Côté client, les récepteurs de canal personnalisés sont insérés dans la chaîne d'objets entre le récepteur de formateur et le dernier récepteur de transport. L'insertion d'un récepteur de canal personnalisé dans le canal serveur ou client vous permet de traiter IMessage lors de l'une ou l'autre étape :

  • Lors du processus durant lequel un appel représenté comme message est converti en flux et envoyé sur le réseau.
  • Lors du processus durant lequel un flux est enlevé du câble et envoyé à l'objet StackBuilderSink (le dernier récepteur de message avant l'objet distant sur le serveur) ou l'objet proxy (sur le client).

Les récepteurs personnalisés peuvent lire ou écrire des données sur le flux (selon si l'appel est sortant ou entrant) et ajouter des informations supplémentaires aux en-têtes là où c'est nécessaire. À cette étape, le message a déjà été sérialisé par le formateur et ne peut pas être modifié. Lorsque l'appel de message est transmis au récepteur de transport au bout de la chaîne, le récepteur de transport écrit les en-têtes dans le flux et transmet le flux au récepteur de transport sur le serveur à l'aide du protocole de transport dicté par le canal.

Récepteurs de transport

Le récepteur de transport est le dernier récepteur dans la chaîne côté client, et le premier récepteur dans la chaîne côté serveur. En plus de transporter le message sérialisé, le récepteur de transport est également chargé d'envoyer les en-têtes au serveur et d'extraire les en-têtes et le flux au retour d'appel du serveur Ces récepteurs sont créés dans le canal et ne peuvent pas être étendus.

Remplacement du formateur par défaut

Comme un canal est un mécanisme de mise en réseau abstrait, vous pouvez configurer le système .NET Remoting pour combiner un canal implémenté par le système avec le formateur de votre choix. Vous pouvez effectuer cette opération à l'aide du constructeur de canal qui prend une implémentation IDictionary des propriétés de canal, un formateur côté serveur et un formateur côté client. Vous pouvez également spécifier le formateur dans un fichier de configuration. L'exemple suivant commande au système de configuration .NET Remoting de créer un HttpChannel mais utilise BinaryClientFormatterSink côté client.

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

Le code suivant effectue la même opération par programme, en supposant un type interface distant IService qui implémente GetServerString et 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 
[C#]
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(null, 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());      
  }
}

Pour obtenir un exemple complet de cette combinaison canal-formateur hébergé dans les services IIS (Internet Information Services), consultez Exemple d'accès distant : hébergement dans Internet Informations Services (IIS).

Pour changer ce client pour utiliser un objet TcpChannel avec l'objet SoapClientFormatterSink, vous ne devez changer que les espaces de noms et l'appel RegisterChannel, comme le montre l'exemple de code suivant.

ChannelServices.RegisterChannel(New TcpChannel(properties, NewSoapClientFormatterSinkProvider(), Nothing))
[C#]
ChannelServices.RegisterChannel(new TcpChannel(null, new SoapClientFormatterSinkProvider(), null));

Voir aussi

Accès distant avancé | Hébergement d'objets distants dans Internet Information Services (IIS) | Exemple d'accès distant : hébergement dans Internet Information Services (IIS)