Мне нужно получить доступ к текущему HttpContext
в статическом или служебном сервисе.
С классическим ASP.NET MVC и System.Web
я просто использовал бы HttpContext.Current
для доступа к контексту статически. Но как это сделать в ASP.NET Core?
Мне нужно получить доступ к текущему HttpContext
в статическом или служебном сервисе.
С классическим ASP.NET MVC и System.Web
я просто использовал бы HttpContext.Current
для доступа к контексту статически. Но как это сделать в ASP.NET Core?
HttpContext.Current
больше не существует в ASP.NET Core, но есть новый IHttpContextAccessor
который вы можете 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*);
}
}
Necromancing.
ДА ВЫ МОЖЕТЕ
Секретный совет для тех, кто переносит большие куски (sigh, Freudian slip) кода.
Следующий метод - злой карбункул взлома, который активно участвует в выполнении экспресс-работы сатаны (в глазах разработчиков платформы .NET Core), , но работает:
В public class Startup
добавить свойство
public IConfigurationRoot Configuration { get; }
И затем добавьте singleton IHttpContextAccessor в DI в 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>();
Затем в Configure
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
, сохраните этот поставщик услуг в статической переменной "ServiceProvider" только что созданного фиктивного класса System.Web.HttpContext(System.Web.HttpContext.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-Forms, вы получите NullReference, когда вы пытаетесь получить доступ к HttpContext, когда его нет, например, он использовался в Application_Start
в global.asax.
Я снова подчеркиваю: это работает только если вы действительно добавили
services.AddSingleton<Microsoft.AspNetCore.Http.IHttpContextAccessor, Microsoft.AspNetCore.Http.HttpContextAccessor>();
как я написал, вы должны.
Добро пожаловать в шаблон ServiceLocator в шаблоне DI;)
Для рисков и побочных эффектов обратитесь к своему резидентному врачу или фармацевту или изучите источники .NET Core на github.com/aspnet и выполните некоторые тесты.
Возможно, более поддерживаемый метод будет добавлять этот вспомогательный класс
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;
}
}
}
}
И затем вызовите HttpContext.Configure в Startup- > 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>()
);
Просто чтобы добавить к другим ответам...
В ASP.NET Core 2.1 есть AddHttpContextAccessor
расширения AddHttpContextAccessor
, который регистрирует IHttpContextAccessor
с правильным временем жизни.
Самый законный способ, с которым я столкнулся, заключался в том, чтобы вставлять IHttpContextAccessor в вашу статическую реализацию следующим образом:
public static class HttpHelper
{
private static IHttpContextAccessor _accessor;
public static void Configure(IHttpContextAccessor httpContextAccessor)
{
_accessor = httpContextAccessor;
}
public static HttpContext HttpContext => _accessor.HttpContext;
}
Затем назначение IHttpContextAccessor в Startup Configure должно выполнять задание.
HttpHelper.Configure(app.ApplicationServices.GetRequiredService<IHttpContextAccessor>());
Думаю, вам также нужно зарегистрировать службу singleton:
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
Согласно этой статье: Доступ к HttpContext вне компонентов фреймворка в ASP.NET Core
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
}
}
Как правило, преобразование приложения Web Forms или MVC5
в ASP.NET Core
потребует значительного объема рефакторинга.
HttpContext.Current
был удален в ASP.NET Core
. Доступ к текущему HTTP-контексту из отдельной библиотеки классов - это тип грязной архитектуры, которую ASP.NET Core
пытается избежать. Есть несколько способов перестроить это в ASP.NET Core
.
Свойство HttpContext
Вы можете получить доступ к текущему HTTP-контексту через свойство HttpContext
на любом контроллере. Самым близким к вашему исходному HttpContext
кода будет передать HttpContext
в метод, который вы вызываете:
public class HomeController : Controller
{
public IActionResult Index()
{
MyMethod(HttpContext);
// Other code
}
}
public void MyMethod(Microsoft.AspNetCore.Http.HttpContext context)
{
var host = $"{context.Request.Scheme}://{context.Request.Host}";
// Other code
}
Параметр HttpContext в промежуточном программном обеспечении
Если вы пишете пользовательское middleware
для конвейера ASP.NET Core
, текущий запрос HttpContext
передается в ваш метод Invoke
:
public Task Invoke(HttpContext context)
{
// Do something with the current HTTP context...
}
Средство доступа к контексту HTTP
Наконец, вы можете использовать вспомогательную службу IHttpContextAccessor
для получения HTTP-контекста в любом классе, который управляется системой внедрения зависимостей ASP.NET Core
. Это полезно, когда у вас есть общая служба, используемая вашими контроллерами.
Запросите этот интерфейс в вашем конструкторе:
public MyMiddleware(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
Затем вы можете получить доступ к текущему HTTP-контексту безопасным способом:
var context = _httpContextAccessor.HttpContext;
//Делаем что-то с current HTTP context
... IHttpContextAccessor
не всегда добавляется в контейнер службы по умолчанию, поэтому зарегистрируйте его в ConfigureServices
просто для безопасности:
public void ConfigureServices(IServiceCollection services)
{
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
// Other code...
}
Просто добавьте это на всякий случай, если у кого-то есть какое-то огромное корпоративное приложение, которое они конвертируют в ядро .net, где везде присутствует HttpContext.Current, но если вы пытаетесь делать это статически и ищете способ подражать этому в .netcore Здесь это решение, но я не рекомендую делать это, если у вас тоже нет.
В запуске
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();
}
}