원격 호스트의 IP 주소를 얻습니다


136

ASP.NET에는 속성 값 의 IP 주소를 제공 할 수있는 속성이 System.Web.HttpRequest포함 된 클래스가 있습니다 .ServerVariablesREMOTE_ADDR

그러나 ASP.NET Web API에서 원격 호스트의 IP 주소를 얻는 비슷한 방법을 찾을 수 없습니다.

요청하는 원격 호스트의 IP 주소를 어떻게 얻을 수 있습니까?

답변:


189

그렇게 할 수는 있지만 검색 할 수는 없습니다. 들어오는 요청에서 속성 백을 사용해야하며 액세스 해야하는 속성은 IIS에서 웹 API를 사용하는지 (웹 호스팅) 또는 자체 호스팅인지에 따라 다릅니다. 아래 코드는이 작업을 수행하는 방법을 보여줍니다.

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는 대부분 매우 깨끗합니다. IP처럼 사소한 것에 이와 같은 코드가 필요하다는 것은 부끄러운 일입니다.
Toad

2
인가 RemoteEndpointMessageProperty의 클래스 System.ServiceModel.Channels, 네임 스페이스 System.ServiceModel.dll조립? WCF에 속한 어셈블리가 아닙니까?
Slauma

4
@Slauma, 그렇습니다. ASP.NET 웹 API는 현재 자체 호스팅 및 웹 호스팅의 두 가지 "flavor"로 구현됩니다. 웹 호스팅 버전은 ASP.NET 위에 구현되고 자체 호스팅 버전은 WCF 리스너 위에 구현됩니다. 플랫폼 (ASP.NET 웹 API) 자체는 호스팅에 구애받지 않으므로 나중에 다른 호스팅을 구현하고 호스트가 해당 속성 (원격 엔드 포인트)을 다르게 표시 할 수 있습니다.
carlosfigueira

3
불행히도 Owin을 사용하여 자체 호스팅하는 경우 (웹 API 2에 권장 됨) 작동하지 않습니다. 있다면 또 다른 필요 ...
Nikolai Samteladze

74

이 솔루션은 또한 Owin을 사용하여 자체 호스팅 된 웹 API를 다룹니다. 여기 에서 부분적으로 .

ApiController웹 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 가지 경우 모두에 대해 라이브러리를로드해야한다는 것입니다. 여기 에서 제안한 것처럼 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 또는 생산성 도구에 의해 자동으로 추가되므로 필수인지 확실하지 않습니다. 어떻게 생각해?
Nikolai Samteladze

나는 여기서 하나의 일을 끝내려고 서둘러 있었고 빌드 오류에 무슨 일이 일어나고 있는지 알기 위해 20 분 이상 걸렸습니다. 방금 코드를 복사하고 클래스를 만들었습니다. 컴파일 할 때 메소드를 표시하지 않고 VS에서 "go to definition"을 사용했을 때 클래스에 데려 갔으며 앞으로 일어날 일을 이해하지 못했습니다. 다른 수업을 찾았습니다. 확장 프로그램은 매우 새로운 기능이며 항상 사용되지는 않습니다. 왜냐하면 이번에는 시간을 절약하는 것이 좋습니다.
바그너 베르톨리 니 주니어 1

1
OWIN을 사용할 때 OwinHttpRequestMessageExtensions를 사용하여 다음과 같은 OWIN 컨텍스트를 얻을 수 있습니다. request.GetOwinContext (). Request.RemoteIpAddress
Stef Heyenrath

1
실제로는 HttpContextWrapper와 같은 var ctx = request.Properties [MsHttpContext] 여야합니다. 당신이 캐스팅 EIF, 당신은 캐스트가 실패 할 경우, 당신은 예외 얻을 수 있기 때문에 널에 확인해야 해달라고
스테프 Heyenrath

31

실제로 하나의 라이너를 원하고 웹 API를 자체 호스팅하지 않으려는 경우 :

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

13

위의 답변에는 속성을 HttpContext 또는 HttpContextWrapper로 캐스팅하려면 System.Web에 대한 참조가 필요합니다. 참조를 원하지 않으면 동적을 사용하여 ip를 얻을 수 있습니다.

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

-1

carlosfigueira가 제공하는 솔루션은 효과가 있지만, 유형이 안전한 원 라이너가 더 좋습니다. 액션 방법에 using System.Web액세스 권한 HttpContext.Current.Request.UserHostAddress을 추가하십시오 .


26
-1 HttpContext.Current작업 파이프 라인에서 올바르게 유지되지 않으므로 웹 API에서 신뢰할 수 없습니다 . 모든 요청 처리가 비동기 적이므로 HttpContext.Current웹 API 코드를 작성할 때 거의 항상 피해야합니다.
Andras Zoltan

@Andras, HttpContext.Current를 사용하는 것이 왜 나쁜지 더 자세히 알고 싶습니다. 귀중한 리소스가 있습니까?
cuongle

13
안녕하세요 @CuongLe; 실제로-스레딩 문제가 문제가 될 수 있지만 ( SynchronizationContext작업간에 올바르게 흐름이있는 경우 항상 직접적이지는 않지만 ); 이것의 가장 큰 문제는 서비스 코드가 자체 호스팅 될 가능성이 높다는 것입니다 (예 : 테스트)- HttpContext.Current순수한 Asp.Net 구조이며 자체 호스팅 할 때는 존재하지 않습니다.
Andras Zoltan

타입 안전이 전부는 아닙니다. 이 코드는 NullReferenceException스레드 (예 : 최신 웹 API 코드에서 매우 일반적인 작업 대기자) 또는 자체 호스팅 컨텍스트에서 사용되는 경우 디버그하기가 어렵습니다 . 적어도 대부분의 다른 답변은 반환 null됩니다.
Aaronaught
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.