.NET 3.0 では当初クライアントのIPアドレスを調べる方法がありませんでしたが、.NET 3.0 SP1 以降は仕様できるようになったようです。
IPアドレスを取得できるのはTCPかHTTP通信を行っている場合に限ります。
実装することになった流れは以下のリンクを参照してください。
Nicholas Allenのブログ
その1 http://blogs.msdn.com/drnick/archive/2007/05/16/client-ip-address.aspx
その2 http://blogs.msdn.com/drnick/archive/2007/09/10/more-about-client-ip-addresses.aspxPhil Henningのブログ
結果こうなりました http://blogs.msdn.com/phenning/archive/2007/08/08/remoteendpointmessageproperty-in-wcf-net-3-5.aspx
先に確認結果から記述すると、同一マシン上で、WCFホスト,WCFクライアント通信ではクライアントのポートアドレスは取得できましたが、IPアドレスはうまく取得できませんでした。
異なるPC上での通信の場合はクライアントのIPアドレスを取得できました。
確認環境は次のとおり(まいど思いつきで書いてます)
- Windows Vista Enterprise(ホスト,クライアント)
- .NET 3.5
- Windows 2003 Server R2 Enterprise Edition(クライアント)
- WCFの通信tプロトコルnet.tcp
1.サービスメソッド上で、クライアントのIPアドレスを取得する
サービスメソッド上でIPを取得するにはメソッドないで、次のように記述します。取得したRemoteEndpointMessagePropertyのAddressとPortプロパティで、クライアントのIPアドレスとポートアドレスを取得します。
なんらかのサービスメソッド内 ... OperationContext.Current.IncomingMessageProperties[System.ServiceModel.Channels.RemoteEndpointMessageProperty.Name]; ....
1.1同一PC上でIPアドレスの取得を行った場合
私の環境では次のように取得されました。なんか値がおかしいのですが、間違っていたらだれか教えて下さい。
補足:enraさんの指摘で::1はIPv6のループバックアドレスということで、一応ただしく取れているという認識でよさそうです。
Address: "::1"
Port: 50464
1.2異なるPC上のクライアントからIPアドレスを取得した場合
私の環境では次のように取得されました。正しく取得できています。
Address: "192.168.0.3
Port: 50213
2.アクセスログを取得に応用してみる
IDispatchMessageInspectorを使用して、クライアントからリクエスト,クライアントへのリスポンス時にSOAPメッセージをフックして、アクセスログを残す方法を記載します。このときにクライアントのIPアドレスを取得機能を利用します。クラス、インタフェースなどの細かい説明はMSDNライブラリを参照してください。処理内容はなんとなくわかると思います。
まず、System.ServiceModel.DispatcherネームスペースのIDispatchServiceMessageInspectorを実装します。
class Interface1 : IDispatchMessageInspector
{
#region IDispatchMessageInspector Member
object IDispatchMessageInspector.AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
{
RemoteEndpointMessageProperty endpoint = request.Properties[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty;
Console.WriteLine("Requested : {0}, from {1}\n body:{2}", request.Headers.Action, endpoint.Address, request.ToString())
return null;
}
void IDispatchMessageInspector.BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
throw new NotImplementedException();
}
#endregion
}
System.ServiceModel.Description.IServiceBehaviorインタフェースをインプリメントします。AddBindingParameters内で、EndpointDispatcherにMessageInspectorを登録します。
class Class1 : IServiceBehavior
{
#region IServiceBehavior Members
void IServiceBehavior.AddBindingParameters(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
}
void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
{
foreach (ChannelDispatcher cd in serviceHostBase.ChannelDispatchers)
{
foreach (EndpointDispatcher ed in cd.Endpoints)
{
ed.DispatchRuntime.MessageInspectors.Add(new Interface1());
}
}
}
void IServiceBehavior.Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
{
}
#endregion
}
あとはサービスをホストするプログラム上で作成したServiceBehaviorを登録します。
host = new ServiceHost(typeof(WcfExample002.ProductService));
host.Description.Behaviors.Add(new Class1());
host.Open();
さんのコメント: さんのコメント: