.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();
さんのコメント: さんのコメント: