領導又有了新的要求,在用戶登錄的時候記錄用戶的IP地址和機器名。
在C#中,獲取本機的機器名和IP地址,甚至網卡的MAC地址,都是很簡單的事情,有封裝好的類和方法可以使用,但現在遇到的問題是,如果客戶端的機器是在另一個局域網內,那網卡的IP地址是局域網地址,這對我們來說沒有用,這就要記錄外網的IP,但是Remoting沒有現成的方法來獲取客戶端的IP,google了一下,網上比較多的是采用在Server端注冊自定義Server Channel Sink,通過Transport Headers來獲取Request的IP。于是我就用了別人寫好的現成的Sink,以及學習了Rickie的一篇《如何定制Sink擴展.Net Remoting功能》。
Rickie的文章:http://www.cnblogs.com/rickie/archive/2004/10/21/54891.html
自定義的Sink的類:http://blog.joycode.com/tingwang/articles/39610.aspx
public class ClientIPServerSinkProvider : IServerChannelSinkProvider

{
private IServerChannelSinkProvider next = null;

public ClientIPServerSinkProvider()

{
}

public ClientIPServerSinkProvider(IDictionary properties, ICollection providerData)

{
}

public void GetChannelData(IChannelDataStore channelData)

{
}

public IServerChannelSink CreateSink(IChannelReceiver channel)

{
IServerChannelSink nextSink = null;
if (next != null)

{
nextSink = next.CreateSink(channel);
}

return new ClientIPServerSink(nextSink);
}

public IServerChannelSinkProvider Next

{

get
{ return next; }

set
{ next = value; }
}
}

public class ClientIPServerSink : BaseChannelObjectWithProperties, IServerChannelSink, IChannelSinkBase

{

private IServerChannelSink _next;

public ClientIPServerSink(IServerChannelSink next)

{
_next = next;
}

public void AsyncProcessResponse(IServerResponseChannelSinkStack sinkStack, Object state, IMessage msg, ITransportHeaders headers, Stream stream)

{
}

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

{
return null;
}

public System.Runtime.Remoting.Channels.ServerProcessing ProcessMessage(IServerChannelSinkStack sinkStack, IMessage requestMsg, ITransportHeaders requestHeaders, Stream requestStream, out IMessage responseMsg, out ITransportHeaders responseHeaders, out Stream responseStream)

{
if (_next != null)

{
IPAddress ip = requestHeaders[CommonTransportKeys.IPAddress] as IPAddress;
Console.WriteLine(ip.ToString());
CallContext.SetData("ClientIPAddress", ip);
ServerProcessing spres = _next.ProcessMessage(sinkStack, requestMsg, requestHeaders, requestStream, out responseMsg, out responseHeaders, out responseStream);

return spres;
}
else

{
responseMsg = null;
responseHeaders = null;
responseStream = null;

return new ServerProcessing();
}
}

public IServerChannelSink NextChannelSink

{

get
{ return _next; }

set
{ _next = value; }
}
}
在Remoting的服務端加入了這個類后,由于我是在IIS上承載的Remoting,所以就需要修改Web.config文件來啟用這個Sink。
<channels>
<channel port="8000" ref="http" name ="httpServer">
<serverProviders>
<formatter ref="soap" typeFilterLevel="Full"/>
<formatter ref="binary" typeFilterLevel="Full"/>
<provider type="Galaxy.Server.Remoting.ClientIPServerSinkProvider, Galaxy.Server.Remoting" />
</serverProviders>
</channel>
<channel port="9000" ref="tcp" name ="tcpServer">
<serverProviders>
<formatter ref="soap" typeFilterLevel="Full"/>
<formatter ref="binary" typeFilterLevel="Full"/>
<provider type="Galaxy.Server.Remoting.ClientIPServerSinkProvider, Galaxy.Server.Remoting" />
</serverProviders>
</channel>
</channels>
做完這個后,以后只需在服務器端通過 ((System.Net.IPAddress)System.Runtime.Remoting.Messaging.CallContext.GetData("ClientIPAddress")).ToString() 就可以獲取Request的IP了。