13

I have hosted WCF 4.5 Restful service in IIS and I am trying to use RemoteEndpointMessageProperty to get the IP address of the client who consumes the service.

Code 1:

private string GetClientIP()
{
  OperationContext context = OperationContext.Current;
  MessageProperties prop = context.IncomingMessageProperties;
  RemoteEndpointMessageProperty endpoint =
         prop[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty;
  string ip = endpoint.Address;
  return ip;
}

Code 2:

private string GetClientIP()
{
  string retIp = string.Empty;
  OperationContext context = OperationContext.Current;
  MessageProperties prop = context.IncomingMessageProperties;
  HttpRequestMessageProperty endpointLoadBalancer =
  prop[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty;
  if (endpointLoadBalancer.Headers["X-Forwarded-For"] != null)
  {
    retIp = endpointLoadBalancer.Headers["X-Forwarded-For"];
  }
  if (string.IsNullOrEmpty(retIp))
  {
    RemoteEndpointMessageProperty endpoint =
                prop[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty;
                retIp = endpoint.Address;
  }
  return retIp;
}

However, since the WCF service is hosted in IIS behind a load balancer, the IP address I got is always the IP of the load balancer. Is there any way to get around this so that I can get the true IP of the client?

RGS
  • 5,131
  • 6
  • 37
  • 65
  • **normally** in a load balancer situation, the load balancer adds a **custom header** to each request with the correct client IP Address... verify with your hosting if that's the case. For example, [CloudFlare](https://www.cloudflare.com) adds a [`HTTP_CF_CONNECTING_IP`](http://stackoverflow.com/a/14985633/28004) header – balexandre Oct 16 '15 at 09:25
  • @balexandre, Is it possible to identify custom headers? – RGS Oct 16 '15 at 09:29
  • 1
    yes, just use a `foreach` loop `foreach(var s in context.Request.Headers) { Log(s, context.Request.Headers[s]); }` and you will see all available headers in the request, even custom ones. – balexandre Oct 16 '15 at 09:31
  • 1
    I had similar issue where WCF i am able to get the client IP using TCP binding but when using another binding (web http), then load balancer IP is passed to service. But i am able to get using "X-Forwarded-For header. Only thing is that httpRequest is passed in properties from load balancer so null checks needs to be added – Mahesh Malpani May 11 '16 at 10:36
  • @MaheshMalpani, Can you post your code? – RGS May 11 '16 at 10:39

2 Answers2

39
OperationContext context = OperationContext.Current;
MessageProperties properties = context.IncomingMessageProperties;
RemoteEndpointMessageProperty endpoint = properties[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty;
string address = string.Empty;
//http://www.simosh.com/article/ddbggghj-get-client-ip-address-using-wcf-4-5-remoteendpointmessageproperty-in-load-balanc.html
if (properties.Keys.Contains(HttpRequestMessageProperty.Name))
{
    HttpRequestMessageProperty endpointLoadBalancer = properties[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty;
    if (endpointLoadBalancer != null && endpointLoadBalancer.Headers["X-Forwarded-For"] != null)
        address = endpointLoadBalancer.Headers["X-Forwarded-For"];
}
if (string.IsNullOrEmpty(address))
{
    address = endpoint.Address;
}

This works in case of load balancer and without it also. I had one endpoint as TCP and other one as web http for REST API.

A.Pissicat
  • 3,023
  • 4
  • 38
  • 93
Mahesh Malpani
  • 1,782
  • 16
  • 27
4

Most Important thing is if you're using

async await 
OperationContext.Current; will be null

My usage is to get Ip so used it like this before any awaitable call

var clientIpAddress = System.Web.HttpContext.Current?.Request?.UserHostAddress;

After the first await statement in your async service operation, OperationContext.Current could be null because the rest of the method body may be running on a different thread (and OperationContext does not flow between threads

So to get it you can write your code before any awaitable action

May be it'll help someone :)

dnxit
  • 7,118
  • 2
  • 30
  • 34