Отримати IP-адресу віддаленого хоста


136

В ASP.NET є System.Web.HttpRequestклас, який містить ServerVariablesвластивість, яка може надати нам IP-адресу зі REMOTE_ADDRзначення властивості.

Однак я не зміг знайти подібний спосіб отримати IP-адресу віддаленого хоста від веб-API ASP.NET.

Як я можу отримати IP-адресу віддаленого хоста, який робить запит?

Відповіді:


189

Це можна зробити, але не дуже відкрито - вам потрібно скористатись пакетом властивостей від вхідного запиту, а властивість, до якої потрібно отримати доступ, залежить від того, чи використовуєте ви веб-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;
}

4
Дякую, я це теж шукав. Незначне вдосконалення = розширення класу: gist.github.com/2653453
MikeJansen

28
WebAPI здебільшого дуже чистий. Прикро, що такий код потрібен для чогось тривіального як ІР.
Жаба

2
Чи RemoteEndpointMessagePropertyклас у System.ServiceModel.Channelsпросторі імен, System.ServiceModel.dllскладання? Хіба це не збори, що належать WCF?
Слаума

4
@Slauma, так, вони є. Веб-API ASP.NET (на даний момент) реалізується у двох "смаках", розміщених самостійно та веб-хостингах. Веб-версія розміщена на версії ASP.NET, тоді як самостійна версія над слухачем WCF. Зауважте, що платформа (ASP.NET Web API) сама по собі хостинг-агностик, тому можливо, що в майбутньому хтось реалізує інший хостинг, і хост буде повертати цю властивість (віддалену кінцеву точку) по-різному.
carlosfigueira

3
На жаль, це не працює, якщо ви самостійно розміщуєте хостинг за допомогою Owin (як це рекомендується для Web API 2). Потрібна інша, якщо там ...
Микола Самтеладзе

74

Це рішення також охоплює веб-API, розміщений самостійно за допомогою Owin. Частково звідси .

Ви можете створити приватний метод у себе, ApiControllerякий повертатиме віддалену IP-адресу незалежно від того, як ви розміщуєте веб-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)

Невелика проблема цього рішення полягає в тому, що вам доведеться завантажувати бібліотеки для всіх 3 випадків, коли ви фактично використовуєте лише одну з них під час виконання. Як запропоновано тут , це можна подолати за допомогою 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.
Вагнер Бертоліні Юніор

@WagnerBertolini, ви правильні, вам потрібна using System.Net.Http;лінія, тому що ви розширюєте HttpRequestMessage. Якщо ви не визначаєте розширення в System.Net.Httpпросторі імен, що дуже сумнівно. Не впевнений, що це важливо, оскільки він буде автоматично доданий будь-яким інструментом IDE або продуктивності. Що ти думаєш?
Микола Самтеладзе

Я поспішав намагатися закінчити одну роботу тут, і мені знадобилося більше 20 хвилин, щоб побачити, що відбувається з помилкою побудови. Я просто скопіював код і створив для нього клас, при його компілюванні він не показував методи, коли я використовував "перейти до визначення" на VS, він взяв мене до свого класу, і я не розумію, що відбувається, поки я не знайшов інший клас. Розширення - це досить нова функція, і вона не використовується весь час, оскільки, я думаю, було б непогано заощадити цей час.
Вагнер Бертоліні Юніор

1
Використовуючи OWIN, ви можете просто використовувати OwinHttpRequestMessageExtensions, щоб отримати контекст OWIN, наприклад: request.GetOwinContext (). Request.RemoteIpAddress
Стеф Хейенрат

1
Насправді це має бути var ctx = request.Properties [MsHttpContext] як HttpContextWrapper; Якщо ви кинете, вам не потрібно перевіряти нуль, тому що якщо випадок не вдасться, ви отримаєте виняток
Стеф Хейенрат

31

Якщо ви дійсно хочете однокласники і не плануєте самостійно розміщувати веб-API:

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

13

Наведені вище відповіді вимагають посилання на System.Web, щоб мати можливість передавати властивість HttpContext або HttpContextWrapper. Якщо ви не хочете посилання, ви можете отримати ip, використовуючи динамічний:

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

-1

Рішення, яке надає carlosfigueira, працює, але краще захистити тип вкладишів: краще додати using System.Webдоступ HttpContext.Current.Request.UserHostAddressдо цього способу дії.


26
-1 цьому веб-api не можна довіряти, оскільки HttpContext.Currentвін не зберігається правильно протягом усієї роботи проекту; оскільки вся обробка запитів асинхронна. HttpContext.Currentмайже завжди слід уникати при написанні коду Web API.
Андрас Золтан

@Andras, я хотів би дізнатися детальніше, чому використання HttpContext.Current є поганим, чи знаєте ви якийсь цінний ресурс для цього?
кунжут

13
Привіт @CuongLe; насправді - в той час, як проблема з ниткою може бути проблемою (хоча не завжди безпосередньо, якщо SynchronizationContextграфіка передається правильно між завданнями); Найбільша проблема з цим полягає в тому, якщо ваш сервісний код коли-небудь буде самостійно розміщений (тестування, наприклад) - HttpContext.Currentце суто конструкція Asp.Net і не існує, коли ви самостійно розміщуєте хостинг.
Андрас Золтан

Безпека типу - це не все. Цей код буде кидати важку для налагодження, NullReferenceExceptionякщо він використовується з потоку (наприклад, офіціант завдань, дуже поширений у сучасному коді Web API) або у власному хості. Принаймні більшість інших відповідей просто повернеться null.
Aaronaught
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.