Partager via


Exemple d'accès distant : CallContext

Cet exemple utilise la classe CallContext et l'interface ILogicalThreadAffinative pour passer des données entre les threads d'un bout à l'autre d'un appel au-delà des limites d'un domaine d'application ou des limites d'un contexte.

Cette application s'exécute sur un ordinateur unique ou sur un réseau. Si vous voulez exécuter cette application sur un réseau, vous devez remplacer "localhost" dans la configuration du client par le nom de l'ordinateur distant.

Bien que cet exemple ne compile pas ServiceClass.vb, il est inclus ici pour illustrer ILogicalThreadAffinative.

Avertissement

.NET Remoting n'effectue aucune authentification ni aucun chiffrement par défaut. Par conséquent, il est recommandé d'effectuer toutes les opérations nécessaires pour vous assurer de l'identité des clients ou des serveurs avant d'interagir avec eux à distance. Étant donné que les applications .NET Remoting exigent les autorisations FullTrust pour s'exécuter, si un client non autorisé se voyait accorder l'accès à votre serveur, il pourrait exécuter du code comme s'il était d'un niveau de confiance suffisant. Authentifiez toujours vos points de terminaison et chiffrez les flux de communication, en hébergeant vos types distants dans IIS (Internet Information Services) ou en créant une paire de récepteurs de canal personnalisée pour effectuer cette tâche.

Pour compiler cet exemple

  • Tapez les commandes suivantes à l'invite de commandes :

    csc /r:System.Runtime.Remoting.dll /t:library ServiceClass.cs

    csc /r:System.Runtime.Remoting.dll /r:ServiceClass.dll client.cs

    vbc /r:System.Runtime.Remoting.dll /r:ServiceClass.dll clientvb.vb

    csc /r:System.Runtime.Remoting.dll /r:ServiceClass.dll server.cs

ServiceClass.cs

using System;
using System.Collections;
using System.Diagnostics;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Contexts;
using System.Runtime.Remoting.Channels;

public class ContextBoundType : ContextBoundObject{

    private DateTime starttime;

   public ContextBoundType(){
      Console.WriteLine("A ContextBoundType instance has been created.");
       starttime = DateTime.Now;
   }

    ~ContextBoundType(){
        Console.WriteLine("ContextBoundType being collected after " + (new TimeSpan(DateTime.Now.Ticks - starttime.Ticks)).ToString() + " seconds.");
    }

   public DateTime GetServerTime(){
       Console.WriteLine("Time requested by a client.");

        // This call overwrites the client's 
        // CallContextString.
        CallContext.SetData("ServerThreadData", new CallContextString("This is the server side replacement."));
      return DateTime.Now;
   }

}

//  One method of communicating between client and server is 
//  to use the CallContext. Calling CallContext essentially puts the data
//  in a Thread Local Store. This means that the information is available 
//  to that thread or that "logical" thread (across application domains) only.
[Serializable]
public class CallContextString : ILogicalThreadAffinative{

    String _str ="";
    public CallContextString(String str){
      _str = str;
      Console.WriteLine("CallContextString created.");
    }

    public override String ToString(){
      return _str;
    }
}

ServiceClass.vb

Ce fichier est inclus uniquement à des fins de documentation.

Imports System
Imports System.Collections
Imports System.Diagnostics
Imports System.Runtime.Remoting
Imports System.Runtime.Remoting.Messaging
Imports System.Runtime.Remoting.Contexts
Imports System.Runtime.Remoting.Channels

Public Class ContextBoundType
   Inherits ContextBoundObject

   Private StartTime As DateTime

   Public Sub New()
      Console.WriteLine("A ContextBoundType instance has been created. (Constructor)")
      StartTime = DateTime.Now
   End Sub  'New

   Protected Overrides Sub Finalize()
      Console.WriteLine("ContextBoundType being collected after " & (New TimeSpan(DateTime.Now.Ticks - starttime.Ticks)).ToString() & " seconds.")
      MyBase.Finalize()
   End Sub   'Finalize

   Public Function GetServerTime() As DateTime
      Console.WriteLine("Time requested by a client.")

      ' This call overwrites the client's 
      ' CallContextString.
      CallContext.SetData("ServerThreadData", New CallContextString("This is the server side replacement."))

      Return DateTime.Now

   End Function  'GetServerTime

End Class 'ContextBoundType


'  One of the methods of communicating between client and server is 
'  to use the CallContext. Calling CallContext essentially puts the data
'  in a Thread Local Store. This means that the information is available 
'  to that thread or that "logical" thread (across application domains) only.
<Serializable> _
Public Class CallContextString
   Implements ILogicalThreadAffinative

   Private _str As String = ""

   Public Sub New(ByVal Contents As String)
      _str = Contents
      Console.WriteLine("CallContextString created with string ""{0}""", Contents)
   End Sub  'New

   Public Overrides Function ToString() As String
      Return _str
   End Function  'ToString

End Class 'CallContextString

ClientVB.vb

Imports System
Imports System.Reflection
Imports System.Runtime.Remoting
Imports System.Runtime.Remoting.Channels
Imports System.Runtime.Remoting.Channels.Tcp
Imports System.Runtime.Remoting.Channels.Http
Imports System.Runtime.Remoting.Contexts
Imports System.Runtime.Remoting.Messaging

Public Class ClientProcess
   <MTAThread()> _
   Public Shared Sub Main()

      Dim Channel As New HttpChannel()
      ChannelServices.RegisterChannel(Channel)

      Dim RemoteType As New WellKnownClientTypeEntry(GetType(ContextBoundType), "https://localhost:8080/TcpCBOService")
      RemotingConfiguration.RegisterWellKnownClientType(RemoteType)

      ' This sets a CallContextDataSlot on this thread. CallContextString      
      ' will convert the ThreadLocalDataStore into a property on the 
      ' message, which will then be merged into the ThreadLocalDataStore 
      ' on the server. This is a nice way to pass information from client 
      ' to server threads and back again. NOTE: This data store has 
      ' logical thread scope. If an application domain has more than one 
      ' thread making calls, each thread will have its own logical 
      ' CallContext, and the server thread will keep each separate.
      CallContext.SetData("ServerThreadData", New CallContextString("This is the thread data inserted on the client thread."))

      Console.WriteLine("CallContextString prior to the call: " & CallContext.GetData("ServerThreadData").ToString())

      Dim service As New ContextBoundType()

      Console.WriteLine("Server time is: " & service.GetServerTime().ToLongTimeString())

      Console.WriteLine("CallContextString after the call: " & CallContext.GetData("ServerThreadData").ToString())

   End Sub   'Main

End Class   'ClientProcess

Client.cs

using System;
using System.Reflection;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Remoting.Channels.Http;
using System.Runtime.Remoting.Contexts;
using System.Runtime.Remoting.Messaging;

public class ClientProcess{

   public static void Main(string[] Args){

        HttpChannel channel = new HttpChannel();
        ChannelServices.RegisterChannel(channel);

        WellKnownClientTypeEntry remotetype = new WellKnownClientTypeEntry(typeof(ContextBoundType),"https://localhost:8080/TcpCBOService");
       RemotingConfiguration.RegisterWellKnownClientType(remotetype);

        // This sets a CallContextDataSlot on this thread. 
        // CallContextString will convert the ThreadLocalDataStore into 
        // a property on the message, which will then be merged into the 
        // ThreadLocalDataStore on the server. This is a nice way to pass 
        // information from client to server threads and back again. 
        // NOTE: This data store has logical thread scope. If an 
        // application domain has more than one thread making calls, 
        // each thread will have its own logical CallContext, and the 
        // server thread will keep each separate.
        CallContext.SetData("ServerThreadData", new CallContextString("This is the thread data inserted on the client thread."));

        Console.WriteLine("CallContextString prior to the call: " + CallContext.GetData("ServerThreadData").ToString());

        ContextBoundType service = new ContextBoundType(); 

        Console.WriteLine("Server time is: " + service.GetServerTime().ToLongTimeString());

        Console.WriteLine("CallContextString after the call: " + CallContext.GetData("ServerThreadData").ToString());

   }
}

Server.cs

using System;
using System.Diagnostics;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Remoting.Channels.Http;
using System.Runtime.Remoting.Contexts;
using System.Runtime.Remoting.Messaging;
using System.Threading;

public class ServerProcess{

   public static void Main(string[] Args){

      HttpChannel channel = new HttpChannel(8080);

      ChannelServices.RegisterChannel(channel);
        
      WellKnownServiceTypeEntry WKSTE = new WellKnownServiceTypeEntry(typeof(ContextBoundType),"TcpCBOService", WellKnownObjectMode.SingleCall);
      RemotingConfiguration.RegisterWellKnownServiceType(WKSTE);

      Console.WriteLine("Press enter to stop this process.");
      Console.ReadLine();

   }

}

Voir aussi

Référence

CallContext
ILogicalThreadAffinative

Autres ressources

Exemples d'accès distant