2012-03-05 4 views
117

В ASP.NET существует класс System.Web.HttpRequest, который содержит ServerVariables свойство, которое может предоставить нам IP-адрес от REMOTE_ADDR.Получить IP-адрес удаленного хоста

Тем не менее, я не смог найти аналогичный способ получить IP-адрес удаленного хоста из веб-API ASP.NET.

Как получить IP-адрес удаленного хоста, делающего запрос?

ответ

169

Это можно сделать, но не очень легко обнаружить - вам нужно использовать пакет свойств из входящего запроса, а свойство, которое вам нужно получить, зависит от того, используете ли вы веб-API в IIS (веб-хостинг) или резидентный. В приведенном ниже коде показано, как это можно сделать.

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; 
} 
+0

Спасибо! Просто небольшое исправление - HttpContextWrapper следует использовать вместо HttpContext. –

+4

Спасибо, я тоже искал это. Незначительное улучшение = класс расширения: https://gist.github.com/2653453 – MikeJansen

+22

WebAPI по большей части очень чистый. Жаль, что такой код необходим для чего-то тривиального, как IP. – Toad

-1

Решение, предлагаемое carlosfigueira работ, но типизированные однострочечники лучше: Добавить using System.Web затем получить доступ к HttpContext.Current.Request.UserHostAddress в методе действий.

+26

-1 этому нельзя доверять в веб-api, потому что 'HttpContext.Current' не является сохраняются правильно во всех задачах; поскольку вся обработка запросов асинхронна. «HttpContext.Current» почти всегда следует избегать при написании кода Web API. –

+0

@ Андра, мне хотелось бы узнать подробнее, почему использование HttpContext.Current плохо, знаете ли вы какой-либо ценный ресурс для этого? –

+13

Hi @CuongLe; на самом деле - в то время как проблема потоковой передачи может быть проблемой (хотя не всегда напрямую, если «SynchronizationContext» правильно протекает между задачами); самая большая проблема заключается в том, что ваш код обслуживания всегда будет самообслуживаться (например, тестирование) - «HttpContext.Current» является чисто конструкцией Asp.Net и не существует, когда вы сами принимаете. –

29

Если вы действительно хотите один вкладыш и не планируете самостоятельно принимающую Web API:

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

Это решение также включает Web API резидентный с помощью Owin. Частично от here.

Вы можете создать частный метод в вас ApiController, что не будет возвращать удаленный IP-адрес, независимо от того, как вы размещаете свой Web API:

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)

Небольшая проблема с этим решением заключается в том, что вам нужно загружать библиотеки для всех трех случаев, когда вы фактически используете только один из них во время выполнения. Как предложено 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(); 
    } 
} 
+1

Это решение должно использовать это пространство имен «System.Net.Http» для работы. Поскольку это имя класса в Assembly System.Web.Http.dll, v5.2.2.0. –

+0

@WagnerBertolini, вы правы, вам нужно 'using System.Net.Http;' line, потому что вы расширяете 'HttpRequestMessage'. Если вы не определяете расширение в пространстве имен System.Net.Http, которое очень сомнительно. Не уверен, что это важно, потому что оно будет автоматически добавлено с помощью любого IDE или инструмента повышения производительности. Как вы думаете? –

+0

Я торопился, пытаясь закончить здесь одну работу, и мне потребовалось больше 20 минут, чтобы посмотреть, что происходит с ошибкой сборки. Я просто скопировал код и создал для него класс, при компиляции он не показывал методы, когда я использовал «перейти к определению» на VS, он взял меня в мой класс, и я не понимаю, что происходит, пока я нашел другой класс. Расширения являются довольно новой функцией и не используются все время, так как, я думаю, было бы неплохо сохранить это время. –

13

Выше ответы требуют ссылки на System.Web, чтобы иметь возможность бросить свойство HttpContext или HttpContextWrapper. Если вам не нужна эта ссылка, вы можете получить IP-адрес с помощью динамического:

var host = ((dynamic)request.Properties["MS_HttpContext"]).Request.UserHostAddress; 
Смежные вопросы