ASP.NET Coreで現在のHttpContextにアクセスする


132

HttpContext静的メソッドまたはユーティリティサービスでcurrent にアクセスする必要があります。

従来のASP.NET MVCとではSystem.WebHttpContext.Current静的にコンテキストにアクセスするために使用するだけでした。しかし、ASP.NET Coreでこれを行うにはどうすればよいですか?

回答:


149

HttpContext.CurrentASP.NET Coreにはもう存在しませんがIHttpContextAccessor、依存関係に挿入して現在を取得するために使用できる新しいものがあり ますHttpContext

public class MyComponent : IMyComponent
{
    private readonly IHttpContextAccessor _contextAccessor;

    public MyComponent(IHttpContextAccessor contextAccessor)
    {
        _contextAccessor = contextAccessor;
    }

    public string GetDataFromSession()
    {
        return _contextAccessor.HttpContext.Session.GetString(*KEY*);
    }
}

3
いい視点ね!またIHttpContextAccessor、DIコンテナーがインスタンスを解決している場所でのみ使用できることにも言及する価値があります。
tugberk

6
@tugberkは、理論的には、CallContextServiceLocatorDIを使用しないインスタンスからでも、サービスを解決するために使用できますCallContextServiceLocator.Locator.ServiceProvider.GetService<IHttpContextAccessor>()。あなたはそれを避けることができれば実際には、それは素晴らしいことだ:)
ケビン・シャレー

17
CallContextServiceLocatorを使用しないでください
davidfowl 2015

9
@davidfowl有効な技術的理由がない限り(もちろん、「静力学は悪である」は別として)、他に選択の余地がなければ人々はそれを使用するでしょう。
ケビン・シャレー

7
もちろん、人々が有効な技術的理由を持つことはめったにありません。静的を使用する方が簡単で、テスト容易性を気にかける人に似ています:)
davidfowl '7/07/15

35

ネクロマンシング。
はい、
大規模に移行する人のための秘訣がらくたコードのチャンク(ため息、フロイトのスリップ)。
次の方法は、悪意のある悪意のある作業を積極的に実行している(.NET Coreフレームワーク開発者の目には当てはまります)、ハックの邪悪なカーバンクルですが、機能します。

public class Startup

プロパティを追加する

public IConfigurationRoot Configuration { get; }

次に、ConfigureServicesのDIにシングルトンIHttpContextAccessorを追加します。

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<Microsoft.AspNetCore.Http.IHttpContextAccessor, Microsoft.AspNetCore.Http.HttpContextAccessor>();

次に、構成で

    public void Configure(
              IApplicationBuilder app
             ,IHostingEnvironment env
             ,ILoggerFactory loggerFactory
    )
    {

DIパラメータを追加するとIServiceProvider svp、メソッドは次のようになります。

    public void Configure(
           IApplicationBuilder app
          ,IHostingEnvironment env
          ,ILoggerFactory loggerFactory
          ,IServiceProvider svp)
    {

次に、System.Webの置換クラスを作成します。

namespace System.Web
{

    namespace Hosting
    {
        public static class HostingEnvironment 
        {
            public static bool m_IsHosted;

            static HostingEnvironment()
            {
                m_IsHosted = false;
            }

            public static bool IsHosted
            {
                get
                {
                    return m_IsHosted;
                }
            }
        }
    }


    public static class HttpContext
    {
        public static IServiceProvider ServiceProvider;

        static HttpContext()
        { }


        public static Microsoft.AspNetCore.Http.HttpContext Current
        {
            get
            {
                // var factory2 = ServiceProvider.GetService<Microsoft.AspNetCore.Http.IHttpContextAccessor>();
                object factory = ServiceProvider.GetService(typeof(Microsoft.AspNetCore.Http.IHttpContextAccessor));

                // Microsoft.AspNetCore.Http.HttpContextAccessor fac =(Microsoft.AspNetCore.Http.HttpContextAccessor)factory;
                Microsoft.AspNetCore.Http.HttpContext context = ((Microsoft.AspNetCore.Http.HttpContextAccessor)factory).HttpContext;
                // context.Response.WriteAsync("Test");

                return context;
            }
        }


    } // End Class HttpContext 


}

次に、を追加したConfigureで、IServiceProvider svpこのサービスプロバイダーを、作成したダミークラスSystem.Web.HttpContext(System.Web.HttpContext.ServiceProvider)の静的変数「ServiceProvider」に保存します。

そしてHostingEnvironment.IsHostedをtrueに設定します

System.Web.Hosting.HostingEnvironment.m_IsHosted = true;

これは基本的にSystem.Webが行ったことですが、見たことがないだけです(変数がパブリックではなく内部として宣言されていると思います)。

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IServiceProvider svp)
{
    loggerFactory.AddConsole(Configuration.GetSection("Logging"));
    loggerFactory.AddDebug();

    ServiceProvider = svp;
    System.Web.HttpContext.ServiceProvider = svp;
    System.Web.Hosting.HostingEnvironment.m_IsHosted = true;


    app.UseCookieAuthentication(new CookieAuthenticationOptions()
    {
        AuthenticationScheme = "MyCookieMiddlewareInstance",
        LoginPath = new Microsoft.AspNetCore.Http.PathString("/Account/Unauthorized/"),
        AccessDeniedPath = new Microsoft.AspNetCore.Http.PathString("/Account/Forbidden/"),
        AutomaticAuthenticate = true,
        AutomaticChallenge = true,
        CookieSecure = Microsoft.AspNetCore.Http.CookieSecurePolicy.SameAsRequest

       , CookieHttpOnly=false

    });

ASP.NET Webフォームと同様に、global.asaxにあったようなHttpContextがない場合にHttpContextにアクセスしようとすると、NullReferenceを取得しますApplication_Start

私は再び強調します、これは実際に追加した場合にのみ機能します

services.AddSingleton<Microsoft.AspNetCore.Http.IHttpContextAccessor, Microsoft.AspNetCore.Http.HttpContextAccessor>();

私が書いたように。
DIパターン内のServiceLocatorパターンへようこそ;)
リスクと副作用については、担当の医師または薬剤師に尋ねるか、またはgithub.com/aspnetで.NET Coreのソースを調べて、いくつかのテストを行ってください。


おそらく、より保守しやすい方法は、このヘルパークラスを追加することです。

namespace System.Web
{

    public static class HttpContext
    {
        private static Microsoft.AspNetCore.Http.IHttpContextAccessor m_httpContextAccessor;


        public static void Configure(Microsoft.AspNetCore.Http.IHttpContextAccessor httpContextAccessor)
        {
            m_httpContextAccessor = httpContextAccessor;
        }


        public static Microsoft.AspNetCore.Http.HttpContext Current
        {
            get
            {
                return m_httpContextAccessor.HttpContext;
            }
        }


    }


}

そして、Startup-> ConfigureでHttpContext.Configureを呼び出します

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IServiceProvider svp)
{
    loggerFactory.AddConsole(Configuration.GetSection("Logging"));
    loggerFactory.AddDebug();


    System.Web.HttpContext.Configure(app.ApplicationServices.
        GetRequiredService<Microsoft.AspNetCore.Http.IHttpContextAccessor>()
    );

37
THIS IS PURE EVIL
Art

2
ヘルパーメソッドを備えたバージョンは、各シナリオで適切に機能します。マルチスレッディング、非同期、およびライフタイムの異なるIoCコンテナーのサービスを考えていますか?
Tamas Molnar 2017

7
これがどれほどひどく悪魔的であるかを指摘するために、私たち全員が邪魔をする必要があることはわかっています...しかし、巨大なプロジェクトをCoreに移植する場合、HttpContext.Currentは到達しにくい静的クラスで使用されていました。 。これはおそらく非常に便利でしょう。そこで、私はそれを言った。
ブライアンマッケイ2017

2
これは純粋な悪であり、ハロウィーンに実装するのに適しています。DIとIoCは大好きですが、悪質な静的変数を持つ悪質な静的クラスを持つレガシーアプリを扱っています。Kestrelを使用してプッシュする必要があり、HttpContextを挿入しようとすると、すべてを壊すことなく元に戻すことができます。
デクスターの家

2
はい、これはMIGRATIONSの正解です。;)
Tom Stickel

23

他の答えに追加するだけです...

ASP.NETコア2.1で、あります拡張メソッド登録されます、正しい寿命とは:AddHttpContextAccessorIHttpContextAccessor

public void ConfigureServices(IServiceCollection services)
{
    services.AddHttpContextAccessor();

    // Other code...
}

2
サタンのカーバンクルのより公式な代替品を見てうれしい!
ケン・リヨン

@ケンリヨン:;)ケラン:シングルトンは正しい寿命です。スコープが間違っています。あるいは、少なくとも執筆時点ではそうでした。ただし、特定のフレームワークバージョンの参照を必要とせずに、AddHttpContextAccessorが正しくそれを実行すればなおさらです。
Stefan Steiger

例を挙げていただけますか?
ツールキット

@Toolkitいくつかのサンプルコードを追加しました。ただし、上記のテキストに対してどのような値を提供するかはわかりません。
ケラン

22

私が思いついた最も正当な方法は、次のように静的実装にIHttpContextAccessorを注入することでした。

public static class HttpHelper
{
     private static IHttpContextAccessor _accessor;
     public static void Configure(IHttpContextAccessor httpContextAccessor)
     {
          _accessor = httpContextAccessor;
     }

     public static HttpContext HttpContext => _accessor.HttpContext;
}

次に、Startup ConfigureでIHttpContextAccessorを割り当てると、ジョブが実行されます。

HttpHelper.Configure(app.ApplicationServices.GetRequiredService<IHttpContextAccessor>());

サービスシングルトンも登録する必要があると思います。

services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

綺麗な。医者が注文したものだけです!
ShrapNull

5

この記事によると:ASP.NET Coreのフレームワークコンポーネント外でのHttpContextへのアクセス

namespace System.Web
{
    public static class HttpContext
    {
        private static IHttpContextAccessor _contextAccessor;

        public static Microsoft.AspNetCore.Http.HttpContext Current => _contextAccessor.HttpContext;

        internal static void Configure(IHttpContextAccessor contextAccessor)
        {
            _contextAccessor = contextAccessor;
        }
    }
}

次に:

public static class StaticHttpContextExtensions
{
    public static void AddHttpContextAccessor(this IServiceCollection services)
    {
        services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
    }

    public static IApplicationBuilder UseStaticHttpContext(this IApplicationBuilder app)
    {
        var httpContextAccessor = app.ApplicationServices.GetRequiredService<IHttpContextAccessor>();
        System.Web.HttpContext.Configure(httpContextAccessor);
        return app;
    }
}

次に:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddHttpContextAccessor();
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseStaticHttpContext();
        app.UseMvc();
    }
}

次のように使用できます。

using System.Web;

public class MyService
{
   public void DoWork()
   {
    var context = HttpContext.Current;
    // continue with context instance
   }
}

2

スタートアップ中

services.AddHttpContextAccessor();

コントローラ内

public class HomeController : Controller
    {
        private readonly IHttpContextAccessor _context;

        public HomeController(IHttpContextAccessor context)
        {
            _context = context; 
        }
        public IActionResult Index()
        {
           var context = _context.HttpContext.Request.Headers.ToList();
           return View();
        }
   }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.