Acceda al HttpContext actual en ASP.NET Core
Necesito acceder a la corriente HttpContext
en un método estático o en un servicio público.
Con ASP.NET MVC y System.Web
, solo lo usaría HttpContext.Current
para acceder al contexto de forma estática. Pero, ¿cómo hago esto en ASP.NET Core?
HttpContext.Current
ya no existe en ASP.NET Core, pero hay una novedad IHttpContextAccessor
que 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*);
}
}
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_Start
global.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>()
);
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>();