2009-02-09 7 views
7

Compte tenu de cette classe MarshalByRef:Identification du client au cours d'une .NET Remoting invocation

public class MyRemotedClass : MarshalByRef 
{ 
    public void DoThis() 
    { 
    ... 
    } 
    public void DoThat() 
    { 
    ... 
    } 
} 

code côté client:

MyRemotedClass m = GetSomehowMyRemotedClass(); 
m.DoThis(); 
m.DoThat(); 

je peux avoir plusieurs clients faire la même chose à la fois. Je voudrais distinguer les clients. Comment puis-je m'identifier dans les méthodes à distance, par qui l'appel à distance est exécuté? Par exemple, je pourrais enregistrer qui a fait quoi. (En fait, je ne ai pas besoin de remonter la vraie information client, je veux juste être en mesure de les invocations de groupe par les clients.)

[Edité pour ajouter plus d'informations de fond]

Je quantité énorme code couvrir, y compris les propriétés. Par conséquent, l'extension de la liste des paramètres d'entrée n'est pas une option.

Répondre

15

L'une des choses que vous pouvez faire est d'identifier un client par adresse IP en implémentant un IServerChannelSinkProvider.

Ajouter cette classe à votre Remoting projet d'accueil:

ClientIPServerSinkProvider.cs

using System; 
using System.Collections; 
using System.IO; 
using System.Runtime.Remoting; 
using System.Runtime.Remoting.Messaging; 
using System.Runtime.Remoting.Channels; 
using System.Threading; 
using System.Net; 

namespace MyRemotingEnvironment 
{ 
    public class ClientIPServerSinkProvider : 
     IServerChannelSinkProvider 
    { 
     private IServerChannelSinkProvider _nextProvider = null; 

     public ClientIPServerSinkProvider() 
     { 
     } 

     public ClientIPServerSinkProvider(
      IDictionary properties, 
      ICollection providerData) 
     { 
     } 

     public IServerChannelSinkProvider Next 
     { 
      get { return _nextProvider; } 
      set { _nextProvider = value; } 
     } 

     public IServerChannelSink CreateSink(IChannelReceiver channel) 
     { 
      IServerChannelSink nextSink = null; 

      if (_nextProvider != null) 
      { 
       nextSink = _nextProvider.CreateSink(channel); 
      } 
      return new ClientIPServerSink(nextSink); 
     } 

     public void GetChannelData(IChannelDataStore channelData) 
     { 
     } 
    } 



    public class ClientIPServerSink : 
     BaseChannelObjectWithProperties, 
     IServerChannelSink, 
     IChannelSinkBase 
    { 

     private IServerChannelSink _nextSink; 

     public ClientIPServerSink(IServerChannelSink next) 
     { 
      _nextSink = next; 
     } 

     public IServerChannelSink NextChannelSink 
     { 
      get { return _nextSink; } 
      set { _nextSink = value; } 
     } 

     public void AsyncProcessResponse(
      IServerResponseChannelSinkStack sinkStack, 
      Object state, 
      IMessage message, 
      ITransportHeaders headers, 
      Stream stream) 
     { 
      IPAddress ip = headers[CommonTransportKeys.IPAddress] as IPAddress; 
      CallContext.SetData("ClientIPAddress", ip); 
      sinkStack.AsyncProcessResponse(message, headers, stream); 
     } 

     public Stream GetResponseStream(
      IServerResponseChannelSinkStack sinkStack, 
      Object state, 
      IMessage message, 
      ITransportHeaders headers) 
     { 

      return null; 

     } 


     public ServerProcessing ProcessMessage(
      IServerChannelSinkStack sinkStack, 
      IMessage requestMsg, 
      ITransportHeaders requestHeaders, 
      Stream requestStream, 
      out IMessage responseMsg, 
      out ITransportHeaders responseHeaders, 
      out Stream responseStream) 
     { 
      if (_nextSink != null) 
      { 
       IPAddress ip = 
        requestHeaders[CommonTransportKeys.IPAddress] as IPAddress; 
       CallContext.SetData("ClientIPAddress", ip); 
       ServerProcessing spres = _nextSink.ProcessMessage(
        sinkStack, 
        requestMsg, 
        requestHeaders, 
        requestStream, 
        out responseMsg, 
        out responseHeaders, 
        out responseStream); 
       return spres; 
      } 
      else 
      { 
       responseMsg = null; 
       responseHeaders = null; 
       responseStream = null; 
       return new ServerProcessing(); 
      } 
     } 


    } 
} 

Ensuite, lorsque vous démarrez votre hôte Remoting faire quelque chose comme ce qui suit:

BinaryServerFormatterSinkProvider bp = new BinaryServerFormatterSinkProvider(); 
ClientIPServerSinkProvider csp = new ClientIPServerSinkProvider(); 
csp.Next = bp; 
Hashtable ht = new Hashtable(); 
ht.Add("port", "1234"); // Your remoting port number 
TcpChannel channel = new TcpChannel(ht, null, csp); 
ChannelServices.RegisterChannel(channel, false); 

RemotingConfiguration.RegisterWellKnownServiceType(
    typeof(MyRemotedClass), 
    "MyRemotedClass.rem", 
    WellKnownObjectMode.SingleCall); 

Dans votre méthode vous appelle peut accéder à l'adresse IP du client en faisant:

public class MyRemotedClass : MarshalByref 
{ 
    public void DoThis() 
    { 
     string clientIP = CallContext.GetData("ClientIPAddress").ToString(); 
    } 
} 
+4

Est-ce vraiment compliqué d'obtenir une adresse IP de client? – IAbstract

+2

@dboarman - c'est le seul moyen. Mais si vous vous êtes habitué à écrire vos propres classes de puits de canaux, cela devient une partie normale de la vie à distance. – Kev

+0

Oui, malheureusement pour moi c'est vraiment ma première incursion dans Remoting ... que je mets de côté pour l'instant. Je ne tiens pas à utiliser Remoting quand je pourrais implémenter protobuf-net de Marc Gravell :) Je vais dans une direction légèrement différente pour l'instant ... merci pour votre aide, tho. – IAbstract

Questions connexes