ASP.NET Core에서 현재 HttpContext에 액세스


132

현재에 액세스해야합니다 HttpContext정적 메소드 또는 유틸리티 서비스에서 에 .

고전적인 ASP.NET MVC 및 을 사용하면 컨텍스트에 정적으로 액세스하는 데 System.Web사용 HttpContext.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
좋은 지적! IHttpContextAccessorDI 컨테이너가 인스턴스를 해결하는 장소에서만 사용할 수 있다는 점도 언급 할 가치 가 있습니다.
tugberk

6
@ tugberk 음, 이론적 CallContextServiceLocator으로는 DI를 주입하지 않은 인스턴스에서도 서비스를 해결하는 데 사용할 수 있습니다 CallContextServiceLocator.Locator.ServiceProvider.GetService<IHttpContextAccessor>(). 실제로, 당신이 그것을 피할 수 있다면 그것은 큰 일입니다 :)
Kévin Chalet


9
@davidfowl은 유효한 기술적 이유가 없다면 (물론 '정적은 악의적 인 것'을 제외하고) 다른 선택이 없다면 사람들이 그것을 사용할 것이라고 확신합니다.
Kévin Chalet

7
물론 사람들은 기술적 인 이유가 거의 없습니다. 정적을 사용하는 것이 더 쉽고 테스트 가능성에 관심이있는 사람과 비슷합니다.
davidfowl

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 Parameter를 추가하면 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이 한 일입니다. 단지 보지 못했습니다 (변수가 public 대신 내부로 선언 된 것 같습니다).

// 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-Forms에서와 같이 Application_Startglobal.asax 와 같이 HttpContext가 없을 때 HttpContext에 액세스하려고하면 NullReference가 발생합니다 .

다시 강조합니다. 실제로 추가 한 경우에만 작동합니다

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
이것은 순수한 사악함
Art

2
헬퍼 메소드가있는 버전이 각 시나리오에서 올바르게 작동합니까? 수명이 다른 IoC 컨테이너의 멀티 스레딩, 비동기 및 서비스를 생각하십니까?
Tamas Molnar

7
나는 우리가 얼마나 악마 같은 일인지 지적하기 위해 우리의 길을 떠나야한다는 것을 알고 있습니다 ...하지만 거대한 프로젝트를 Core로 이식하는 경우 HttpContext.Current가 도달하기 어려운 정적 클래스에서 사용되었습니다. 이것은 아마도 매우 유용 할 것입니다. 나는 말했다.
Brian MacKay

2
이것은 순수한 악입니다 ... 그리고 나는 그것을 할로윈에 구현하려고합니다. 나는 DI와 IoC를 좋아하지만 악한 정적 변수가있는 악한 정적 클래스가있는 레거시 응용 프로그램을 다루고 있습니다 .Kestrel을 사용하여 푸시하고 HttpContext를 주입하려고하면 모든 것을 깨지 않고도 실행을 취소 할 수 있습니다.
덱스터의 집

2
예, 이것은 마이그레이션에 대한 정답입니다. ;)
Tom Stickel

23

다른 답변에 추가하려면 ...

ASP.NET 코어 2.1, 거기에 확장 방법은 그이 등록됩니다, 정확한 수명과 :AddHttpContextAccessorIHttpContextAccessor

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

    // Other code...
}

2
사탄의 탄수화물에 대한 더 공식적인 대안을 보게되어 기쁘다!
Ken Lyon

@Ken Lyon :;) khellang : 싱글 톤이 올바른 수명입니다. 범위가 잘못되었습니다. 또는 적어도 글을 쓰는 시점에는 그랬습니다. 그러나 AddHttpContextAccessor가 특정 프레임 워크 버전에 대한 참조가 필요없이 올바르게 수행하면 더 좋습니다.
Stefan Steiger

예를 들어 주시겠습니까?
툴킷

@Toolkit 예제 코드를 추가했습니다. 그러나 위의 텍스트에 어떤 가치를 제공하는지 확실하지 않습니다.
Khellang

22

내가 만든 가장 합법적 인 방법은 다음과 같이 정적 구현에 IHttpContextAccessor를 주입하는 것입니다.

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

     public static HttpContext HttpContext => _accessor.HttpContext;
}

그런 다음 시작 구성에서 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.