Acceda al HttpContext actual en ASP.NET Core

Resuelto maxswitcher asked hace 9 años • 7 respuestas

Necesito acceder a la corriente HttpContexten un método estático o en un servicio público.

Con ASP.NET MVC y System.Web, solo lo usaría HttpContext.Currentpara acceder al contexto de forma estática. Pero, ¿cómo hago esto en ASP.NET Core?

maxswitcher avatar Jul 06 '15 17:07 maxswitcher
Aceptado

HttpContext.Currentya no existe en ASP.NET Core, pero hay una novedad IHttpContextAccessorque puede inyectar en sus dependencias y usar para recuperar el actual HttpContext:

public class MyComponent : IMyComponent
{
    private readonly IHttpContextAccessor _contextAccessor;

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

    public string GetDataFromSession()
    {
        return _contextAccessor.HttpContext.Session.GetString(*KEY*);
    }
}
Kévin Chalet avatar Jul 06 '2015 10:07 Kévin Chalet

Consejo secreto para quienes migran grandes cantidades de código.

El siguiente método es un ántrax malvado de un hack que participa activamente en llevar a cabo el trabajo expreso de Satanás (a los ojos de los desarrolladores del marco .NET Core), pero funciona :

Enpublic class Startup

agregar una propiedad

public IConfigurationRoot Configuration { get; }

Y luego agregue un IHttpContextAccessor singleton a DI en ConfigureServices.

    // 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>();

Luego en Configurar

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

agregue el parámetro DI IServiceProvider svp, para que el método se vea así:

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

A continuación, cree una clase de reemplazo para 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 


}

Ahora en Configurar, donde agregó IServiceProvider svp, guarde este proveedor de servicios en la variable estática "ServiceProvider" en la clase ficticia recién creada System.Web.HttpContext (System.Web.HttpContext.ServiceProvider)

y establezca HostingEnvironment.IsHosted en verdadero

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

Esto es esencialmente lo que hizo System.Web, solo que nunca lo viste (supongo que la variable fue declarada como interna en lugar de pública).

// 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
     
    });

Al igual que en ASP.NET Web-Forms, obtendrá una referencia nula cuando intente acceder a un HttpContext cuando no hay ninguno, como solía estar en Application_Startglobal.asax.

Lo enfatizo nuevamente, esto solo funciona si realmente agregaste

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

como escribí que deberías.
Bienvenido al patrón ServiceLocator dentro del patrón DI;)
Para conocer los riesgos y efectos secundarios, consulte a su médico residente o farmacéutico, o estudie las fuentes de .NET Core en github.com/aspnet y realice algunas pruebas.


Quizás un método más fácil de mantener sería agregar esta clase auxiliar

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;
            }
        }


    }


}

Y luego llamando a HttpContext.Configure en Inicio->Configurar

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>()
    );
Stefan Steiger avatar Oct 13 '2016 18:10 Stefan Steiger

La forma más legítima que se me ocurrió fue inyectando IHttpContextAccessor en su implementación estática de la siguiente manera:

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

     public static HttpContext HttpContext => _accessor.HttpContext;
}

Luego, asignar IHttpContextAccessor en la Configuración de inicio debería funcionar.

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

Supongo que también deberías necesitar registrar el servicio singleton:

services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
Jan avatar Jul 30 '2017 20:07 Jan