リモートホストのIPアドレスを取得する


136

ASP.NETには、プロパティ値からIPアドレスを提供できるプロパティをSystem.Web.HttpRequest含むクラスがあります。ServerVariablesREMOTE_ADDR

ただし、ASP.NET Web APIからリモートホストのIPアドレスを取得する同様の方法が見つかりませんでした。

リクエストを行っているリモートホストのIPアドレスを取得するにはどうすればよいですか?

回答:


189

それを行うことは可能ですが、それほど発見することはできません。受信したリクエストからプロパティバッグを使用する必要があり、アクセスする必要があるプロパティは、IIS(Webホスト)またはセルフホストでWeb 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として些細なものに必要なのは残念です。
2012

2
あるRemoteEndpointMessageProperty中、クラスSystem.ServiceModel.Channels、名前空間のSystem.ServiceModel.dllアセンブリ?それはWCFに属するアセンブリではありませんか?
スラウマ

4
@Slauma、はい、そうです。ASP.NET Web APIは、(現在)セルフホスト型とウェブホスト型の2つの「フレーバー」で実装されています。WebでホストされるバージョンはASP.NETの上に実装され、自己ホストされるバージョンはWCFリスナーの上に実装されます。プラットフォーム(ASP.NET Web API)自体はホスティングに依存しないため、将来誰かが別のホスティングを実装し、ホストがそのプロパティ(リモートエンドポイント)を異なる方法で表示する可能性があることに注意してください。
カルロスフィゲイラ

3
残念ながら、これはOwinを使用してセルフホストする場合は機能しません(Web API 2で推奨されているため)。そこにあればさらに必要です...
ニコライサムテラゼ2013年

74

このソリューションは、Owinを使用してセルフホストされたWeb APIもカバーしています。部分的にはここから。

ApiControllerWeb 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パッケージを使用している場合は、すでにインストールされています)

このソリューションの小さな問題は、実行時に実際にライブラリの1つだけを使用する場合に、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です。
Wagner Bertolini Junior、

@WagnerBertolini、あなたは正しいです、あなたはusing System.Net.Http;あなたが拡張しているのであなたはラインが必要HttpRequestMessageです。あなたがSystem.Net.Http非常に疑わしい名前空間で拡張を定義しているのでない限り。ただし、IDEまたは生産性向上ツールによって自動的に追加されるため、必須かどうかはわかりません。どう思いますか?
Nikolai Samteladze

ここで1つのジョブを完了しようと急いでいたため、ビルドエラーの状況を確認するのに20分以上かかりました。コードをコピーして、そのクラスを作成しました。コンパイル時にメソッドが表示されなかったとき、VSで「定義に移動」を使用したとき、クラスに移動しました。他のクラスを見つけました。拡張機能はかなり新しい機能であり、常に使用されているわけではないので、この時間を節約することをお勧めします。
Wagner Bertolini Junior、

1
OWINを使用する場合、OwinHttpRequestMessageExtensionsを使用して、次のようなOWINコンテキストを取得できます。request.GetOwinContext()。Request.RemoteIpAddress
Stef Heyenrath

1
実際にはvar ctx = request.Properties [MsHttpContext] as HttpContextWrapperである必要があります。Eキャストした場合、nullをチェックする必要はありません。キャストが失敗した場合、例外が発生します
Stef Heyenrath

31

ワンライナーが本当に必要で、Web 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.Webthen thenアクセスHttpContext.Current.Request.UserHostAddressを追加します。


26
-1これはHttpContext.Current、タスクパイプライン全体で正しく保持されないため、Web APIでは信頼できません。すべてのリクエスト処理は非同期であるためです。HttpContext.CurrentWeb APIコードを作成するときは、ほとんど常に回避する必要があります。
Andras Zoltan

@Andras、私はHttpContext.Currentの使用が悪い理由の詳細を知りたいのですが、このための貴重なリソースを知っていますか?
cuongle

13
@CuongLe様 実際-スレッドの問題が問題になる可能性があります(ただしSynchronizationContext、タスク間で正しくフローされている場合は必ずしも直接ではありません)。これに関する最大の問題は、サービスコードがセルフホストされる可能性があるかどうか(テストなど)です- HttpContext.Current純粋にAsp.Net構造であり、セルフホストする場合は存在しません。
Andras Zoltan

タイプセーフがすべてではありません。このコードはNullReferenceException、スレッド(たとえば、最新のWeb APIコードでは非常に一般的なタスク待機者)またはセルフホストコンテキストから使用すると、デバッグが困難になります。少なくとも他のほとんどの答えは単に返されnullます。
アーロンノート、2014年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.