I'm Keyvan Nayyeri, a 28 years old software engineer working at Match.Com and living in Dallas, Texas.
I have a Master’s degree in computer science and a bachelor's degree in applied mathematics. I’m also known to be a technical author with several technical publications in the form of books and articles. Besides, I'm an open source enthusiast and have coordinated or contributed to several projects. Currently, I maintain my projects on GitHub.
As a content provider on the internet, not only I publish on this technical blog, but also I'm a podcaster and publish audio podcasts on Mash This.
Trying to maintain a healthy and active lifestyle, I'm a pescetarianist and exercise almost everyday. I’m an avid runner, soccer defender, and tennis player. I also have an interest in fashion.
One of the features that was missing from WCF 3.0 was the ability to detect client IP address in services. For a technology that is completely built on top of SOA hence a server/client mechanism where clients are an important part of the story this looked like a big lack!
There are various situations where you need to retrieve the client IP address on your service side and there is no doubt that having such a feature can be a common need and request.
However, this is a new feature added to .NET 3.5 and Windows Communication Foundation 3.5 for developers and you're now able to retrieve the client's IP address and port in your code easily.
Suppose that I have a service contract like what you see below where there is a single method to get a string argument and return another string value.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
namespace ClientInfoSample
{
[ServiceContract]
public interface IService
{
[OperationContract]
string GetData(string value);
}
}
Here comes the implementation of this service contract with a very simple code that returns a string including the client's IP address and port.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.ServiceModel.Channels;
namespace ClientInfoSample
{
public class MyService : IService
{
public string GetData(string value)
{
OperationContext context = OperationContext.Current;
MessageProperties messageProperties = context.IncomingMessageProperties;
RemoteEndpointMessageProperty endpointProperty =
messageProperties[RemoteEndpointMessageProperty.Name]
as RemoteEndpointMessageProperty;
return string.Format("Hello {0}! Your IP address is {1} and your port is {2}",
value, endpointProperty.Address, endpointProperty.Port);
}
}
}
You simply can notice that there are a few steps to retrieve the client information from the OperationContext. First you need to get access to the current instance of the OperationContext then retrieve its IncomingMessageProperties as a MessageProperties object. The last step is to create an instance of RemoteEndpointMessageProperty by looking in the MessageProeprties collection for the name of the RemoteEndpointMessageProperty. Now RemoteEndpointMessageProperty has two separate properties to get access to the client's IP address and port.
It's worthwhile to know that behind the scenes WCF is passing the client's IP and port (along some other information) with each message as the properties for the message. This is happening for services hosted on HTTP or TCP protocols so the important point is here and you can't apply this code for other protocols.
I can self-host this service with a simple configuration file that is already generated by Visual Studio 2008 and just needs some modifications to apply new contract and service names.
xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.web>
<compilation debug="true" />
system.web>
<system.serviceModel>
<services>
<service name="ClientInfoSample.MyService" behaviorConfiguration="ClientInfoSample.MyServiceBehavior">
<host>
<baseAddresses>
<add baseAddress = "http://localhost:8731/Design_Time_Addresses/ClientInfoSample/MyService/" />
baseAddresses>
host>
<endpoint address ="" binding="wsHttpBinding" contract="ClientInfoSample.IService">
<identity>
<dns value="localhost"/>
identity>
endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
service>
services>
<behaviors>
<serviceBehaviors>
<behavior name="ClientInfoSample.MyServiceBehavior">
<serviceMetadata httpGetEnabled="True"/>
<serviceDebug includeExceptionDetailInFaults="False" />
behavior>
serviceBehaviors>
behaviors>
system.serviceModel>
configuration>
Hosting and running the service, I can test it quickly to get an output like what you see here:
You can download the source code sample for this post from here.
Paul Fazzino
Jan 28, 2008 11:20 AM
#
Not to bash the article however in an enterprise environment I find client IP is rarely available to an endpoint. By the time the client has jumped through their own proxy and through your own bunch of firewalls, redirectors, NAT'd, etc... the IP address becomes next to useless.
Keyvan Nayyeri
Jan 28, 2008 11:25 AM
#
Yes, you're right on proxies. I was going to mention it in the post but thought it's very obvious point, though.
But don't forget that such information is still useful and important. There are many cases when you need this information.
Shiju
Mar 05, 2008 11:57 PM
#
Hi I tried this [Detect Client IP in WCF 3.5], unfortunitly its not working in other computers. Its returning the proxy IP only. im using basicHttpBinding here.
abraham
Nov 21, 2008 9:12 PM
#
Thank you for the example, this is definitely useful.
Is there some way I can detect the client's URL.
My use case involves clients within a domain accessing my web service. This could involve multiple non-contiguous IP's and the URL would be a much easier value to validate.
Ricky
Jan 30, 2009 11:28 AM
#
I've been trying to implement this for client > service 1 > service2 > service1 > client, but service2 doesn't return the client ip address...any ideas on how to accomplish this?
L
Feb 26, 2009 5:08 PM
#
It always returns 127.0.0.1 (localhost)
mojtaba montazery
Aug 04, 2009 3:59 AM
#
thank keyvan,
when I am using WCF test client everything is OK , but when I am using ServiceProxy(a class library that contains generated class with svcutil.exe) and call function from IIS "OperationContext.Current" is null.
can you help me?
Bradley Ward
Jan 08, 2010 1:20 PM
#
So this is really not an answer to the question of how to get the client IP address.
Does anyone know how to get the REAL client IP address? Just like in a web application, I would like to log the xxx.xxx.xxx.xxx IP address into the log file. All I am getting using this method is an address like fe80::515c:28c9:1cc3:126b%14:51394.
Any ideas anyone?
Thanks
Ahmad Sheikholeslami
Jan 11, 2010 11:34 PM
#
Ali
Feb 13, 2010 4:05 AM
#
thank you dear keyvan.
Luke Venediger
Feb 22, 2010 3:08 AM
#
mahdi
Mar 07, 2010 9:06 AM
#
I need the ip address to log all actions by a service in server , I use net binding , in test everything is ok but i'm afraid in real condition according to above posts it won't work well
but most comments are about http binding but mine is net binding
can everybody tell me is there any difference?
Richard Lee
Aug 02, 2010 5:07 PM
#
The other problem with the above code is that for IPV6 systems (Win7 for example) the WCF only picks up the first IP (usually a LocalSite which is useless) and not the Toledo Address which is annoying. I am finding that I am having to pass it up the line (from Silverlight for eg) and then passing it through/storing it serverside in the WCF (or chain thereof). Messy.
Fourmyle
Aug 05, 2010 11:02 AM
#
Jaikrishan
Dec 28, 2010 4:00 AM
#
My service can contain multiple instances and multiple clients can connect to it.
My service is running only on the user’s PC so getting IP address is not fulfilled my requirement.
I would like to know the information of the client like which application (process id or process name) is consuming my service. So if I need to update my service next version that time I can give appropriate message to client.
Ex: Service is used by the following applications…App1, App2 etc…
Can you please suggest me is there any way to get the information of the client?
I would appreciate your help.
Please forgive me for my bad English.
Thanks In advance.
Jai
Pete
Mar 27, 2011 9:17 AM
#
1. Call yourEndpoint.Contract.Behaviors.Add(New YourContractBehavior())
2. Define a class "YourContractBehavior" to implement IContractBehavior.ApplyDispatchBehavior() by calling dispatchRuntime.ChannelDispatcher.ChannelInitializers.Add(New YourInitializer())
3. Define a class "YourInitializer" to implement IChannelInitializer.Initialize(), which will give you access to the IClientChannel object (which is the ServiceContract class)
4. In the debugger, follow this property chain: channel.Binder.Channel.Connection.Stream.InnerStream.Connection.RemoteIPEndPoint <-- that's it!
Most of the classes along this chain are entirely internal. Using Reflector's "Analyze" feature, it's fairly easy to prove that NO CODE PATH exists that would expose this information via a public API.
In my opinion, this is an inexcusable design flaw of WCF. It's bad design that they didn't make it public, but it's TOTALLY INSANE for it to be buried so ridiculously deep in object tree. The Socket.RemoteEndPoint information has been a standard since the original BSD sockets in the 1970's, and (despite the claims above) it is a very important and valuable piece of information.
Star Liu
Sep 15, 2011 4:13 AM
#
i'm coder in china.
Nice to know you!
Felix
Nov 16, 2011 3:43 PM
#
isingh
Jan 08, 2013 4:32 AM
#
Leave a Comment