2009-02-09 2 views
7

Учитывая этот класс MarshalByRef: код на сторонеИдентификация клиента во время вызова .NET Remoting

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

Client:

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

я могу иметь несколько клиентов делать то же самое в то же время. Я хотел бы отличить клиентов. Как определить методы удаленного доступа, с помощью которых выполняется вызов удаленного вызова? Например, я мог бы написать, кто что сделал. (На самом деле, мне не нужно, чтобы проследить истинную информацию клиента, я просто хочу, чтобы иметь возможность групповых вызовов клиентов.)

[Отредактировано добавить больше справочной информации]

У меня есть огромное количество кода для покрытия, включая свойства. Поэтому расширение списка входных параметров не является вариантом.

ответ

15

Одна из вещей, которую вы можете сделать, это идентифицировать клиента по IP-адресу путем реализации IServerChannelSinkProvider.

Добавить этот класс в проект хоста удаленного взаимодействия:

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(); 
      } 
     } 


    } 
} 

Тогда при запуске удаленного взаимодействия хоста сделать что-то вроде следующего:

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); 

В вашем методе звонит может получить доступ к IP-адресу клиента:

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

Действительно ли это сложно только для получения IP-адреса клиента? – IAbstract

+2

@ dboarman - это единственный способ. Но если вы привыкли писать свои собственные каналы раковины, то это становится нормальной частью жизни. – Kev

+0

Да, к сожалению, для меня это действительно мой первый набег на Remoting ... который я откладываю сейчас. Я не хочу использовать Remoting, когда я могу реализовать protobuf-net Марка Гравелла :) Я сейчас немного в другом направлении ... спасибо за помощь, тo. – IAbstract