获取远程主机的IP地址

时间:2012-03-05 11:30:43

标签: c# asp.net-web-api

在ASP.NET中有一个System.Web.HttpRequest类,其中包含ServerVariables属性,可以为我们提供REMOTE_ADDR属性值的IP地址。

但是,我找不到类似的方法从ASP.NET Web API获取远程主机的IP地址。

如何获取发出请求的远程主机的IP地址?

6 个答案:

答案 0 :(得分:183)

可以这样做,但不是很容易被发现 - 你需要使用传入请求中的属性包,你需要访问的属性取决于你是在IIS(webhosted)下使用Web API还是自己-hosted。下面的代码显示了如何做到这一点。

private string GetClientIp(HttpRequestMessage request)
{
    if (request.Properties.ContainsKey("MS_HttpContext"))
    {
        return ((HttpContextWrapper)request.Properties["MS_HttpContext"]).Request.UserHostAddress;
    }

    if (request.Properties.ContainsKey(RemoteEndpointMessageProperty.Name))
    {
        RemoteEndpointMessageProperty prop;
        prop = (RemoteEndpointMessageProperty)request.Properties[RemoteEndpointMessageProperty.Name];
        return prop.Address;
    }

    return null;
}

答案 1 :(得分:73)

此解决方案还涵盖使用Owin自托管的Web API。部分来自here

您可以在ApiController中创建一个私有方法,无论您如何托管Web API,它都将返回远程IP地址:

 private const string HttpContext = "MS_HttpContext";
 private const string RemoteEndpointMessage =
     "System.ServiceModel.Channels.RemoteEndpointMessageProperty";
 private const string OwinContext = "MS_OwinContext";

 private string GetClientIp(HttpRequestMessage request)
 {
       // Web-hosting
       if (request.Properties.ContainsKey(HttpContext ))
       {
            HttpContextWrapper ctx = 
                (HttpContextWrapper)request.Properties[HttpContext];
            if (ctx != null)
            {
                return ctx.Request.UserHostAddress;
            }
       }

       // Self-hosting
       if (request.Properties.ContainsKey(RemoteEndpointMessage))
       {
            RemoteEndpointMessageProperty remoteEndpoint =
                (RemoteEndpointMessageProperty)request.Properties[RemoteEndpointMessage];
            if (remoteEndpoint != null)
            {
                return remoteEndpoint.Address;
            }
        }

       // Self-hosting using Owin
       if (request.Properties.ContainsKey(OwinContext))
       {
           OwinContext owinContext = (OwinContext)request.Properties[OwinContext];
           if (owinContext != null)
           {
               return owinContext.Request.RemoteIpAddress;
           }
       }

        return null;
 }

所需参考:

  • HttpContextWrapper - System.Web.dll
  • RemoteEndpointMessageProperty - System.ServiceModel.dll
  • OwinContext - Microsoft.Owin.dll(如果您使用Owin包,您将拥有它)

此解决方案的一个小问题是,当您在运行时实际只使用其中一个时,必须为所有3个案例加载库。根据建议here,可以使用dynamic变量来克服这个问题。您还可以将GetClientIpAddress方法写为HttpRequestMethod的扩展名。

using System.Net.Http;

public static class HttpRequestMessageExtensions
{
    private const string HttpContext = "MS_HttpContext";
    private const string RemoteEndpointMessage =
        "System.ServiceModel.Channels.RemoteEndpointMessageProperty";
    private const string OwinContext = "MS_OwinContext";

    public static string GetClientIpAddress(this HttpRequestMessage request)
    {
       // Web-hosting. Needs reference to System.Web.dll
       if (request.Properties.ContainsKey(HttpContext))
       {
           dynamic ctx = request.Properties[HttpContext];
           if (ctx != null)
           {
               return ctx.Request.UserHostAddress;
           }
       }

       // Self-hosting. Needs reference to System.ServiceModel.dll. 
       if (request.Properties.ContainsKey(RemoteEndpointMessage))
       {
            dynamic remoteEndpoint = request.Properties[RemoteEndpointMessage];
            if (remoteEndpoint != null)
            {
                return remoteEndpoint.Address;
            }
        }

       // Self-hosting using Owin. Needs reference to Microsoft.Owin.dll. 
       if (request.Properties.ContainsKey(OwinContext))
       {
           dynamic owinContext = request.Properties[OwinContext];
           if (owinContext != null)
           {
               return owinContext.Request.RemoteIpAddress;
           }
       }

        return null;
    }
}

现在您可以像这样使用它:

public class TestController : ApiController
{
    [HttpPost]
    [ActionName("TestRemoteIp")]
    public string TestRemoteIp()
    {
        return Request.GetClientIpAddress();
    }
}

答案 2 :(得分:30)

如果你真的想要一个单行并且不打算自托管Web API:

((System.Web.HttpContextWrapper)Request.Properties["MS_HttpContext"]).Request.UserHostAddress;

答案 3 :(得分:13)

以上答案需要引用System.Web才能将属性强制转换为HttpContext或HttpContextWrapper。如果您不想参考,您可以使用动态获取IP:

var host = ((dynamic)request.Properties["MS_HttpContext"]).Request.UserHostAddress;

答案 4 :(得分:1)

当服务器位于代理或负载均衡器之后时,标记的解决方案将返回代理的内部 IP 地址。在这种情况下,我们的生产环境使用了负载平衡器,而我们的开发和测试环境没有使用,因此我修改了标记的解决方案,以在同一代码中适应这两种情况。

public string GetSourceIp(HttpRequestMessage httpRequestMessage)
    {
        string result = string.Empty;

        // Detect X-Forwarded-For header
        if (httpRequestMessage.Headers.TryGetValues("X-Forwarded-For", out IEnumerable<string> headerValues))
        {
            result = headerValues.FirstOrDefault();
        }
        // Web-hosting
        else if (httpRequestMessage.Properties.ContainsKey("MS_HttpContext"))
        {
            result = ((HttpContextWrapper)httpRequestMessage.Properties["MS_HttpContext"]).Request.UserHostAddress;
        }
        // Self-hosting
        else if (httpRequestMessage.Properties.ContainsKey(RemoteEndpointMessageProperty.Name))
        {
            RemoteEndpointMessageProperty prop;
            prop = (RemoteEndpointMessageProperty)httpRequestMessage.Properties[RemoteEndpointMessageProperty.Name];
            result = prop.Address;
        }

        return result;
    }

答案 5 :(得分:-1)

carlosfigueira提供的解决方案有效,但类型安全的单行更好:在您的操作方法中添加using System.Web然后访问HttpContext.Current.Request.UserHostAddress