Keyvan Nayyeri

My daily musings about software and technology

Detect Client IP in WCF 3.5

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:

WCF Test Client

You can download the source code sample for this post from here.

19 Comments

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
#
Like others, I want to find the IP address of the client from within my WCF service. I have found numerous posts containing the exact same code shown in this post, and all of them explain that what you get is NOT the client IP address, but rather the IP address that the service sees the client as.

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
#
Thanks , Keyvan jan, besiar alli ...

Ali
Feb 13, 2010 4:05 AM
#
Actually even if you find the client IP address, probably it's not useful, because it might be a private IP address, so it's not necceserilly unique! each proxy add a header to http packet containing the previous IP address. so you will need to retrive an array of these IP addresses to distinguish them. All I'm trying to say is that one IP address is not useful here.
thank you dear keyvan.

Luke Venediger
Feb 22, 2010 3:08 AM
#
I agree with @BradleyWard - I see this example all over the internet but the resultant IP is in IPv6 format - anyone know how to convert it to IPv4?

mahdi
Mar 07, 2010 9:06 AM
#
Thanks for you post
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
#
Luke - IPV4 is 32 bit address whereas IPV6 is 128Bit Addressing - therefore its like trying to convert a BigInt into an Int. There are some utilities that will do this, but they will only really work for IPV4 addresses that have been IPV6 encoded. There are also special IPV6 encodings related to loop back etc too.

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
#
Thanks. Just what i needed.

Jaikrishan
Dec 28, 2010 4:00 AM
#
Hi,
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
#
The remote IP address is hopelessly buried in the WCF internals. You can see it in the debugger by following these steps:

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
#
thanks for the article.
i'm coder in china.
Nice to know you!

Felix
Nov 16, 2011 3:43 PM
#
Thank you, it works

isingh
Jan 08, 2013 4:32 AM
#
Can i access local self-hosted wcf service from server side code like asp.net ? Suppose my page is loaded in cloud and it have single textbox and button. In textbox i enter local address of service and submit... Will it create proxy?

Leave a Comment