在 ASP.NET Core 中访问 HttpContextAccess HttpContext in ASP.NET Core

本文内容

ASP.NET Core 应用通过 IHttpContextAccessor 接口及其默认实现 HttpContextAccessor 访问 HttpContext只有在需要访问服务内的 HttpContext 时,才有必要使用 IHttpContextAccessor

通过 Razor Pages 使用 HttpContextUse HttpContext from Razor Pages

Razor 页面 PageModel 公开 HttpContext 属性:

  1. public class AboutModel : PageModel
  2. {
  3. public string Message { get; set; }
  4. public void OnGet()
  5. {
  6. Message = HttpContext.Request.PathBase;
  7. }
  8. }

通过 Razor 视图使用 HttpContextUse HttpContext from a Razor view

Razor 视图通过视图上的 RazorPage.Context 属性直接公开 HttpContext下面的示例使用 Windows 身份验证检索 Intranet 应用中的当前用户名:

  1. @{
  2. var username = Context.User.Identity.Name;
  3. ...
  4. }

通过控制器使用 HttpContextUse HttpContext from a controller

控制器公开 ControllerBase.HttpContext 属性:

  1. public class HomeController : Controller
  2. {
  3. public IActionResult About()
  4. {
  5. var pathBase = HttpContext.Request.PathBase;
  6. ...
  7. return View();
  8. }
  9. }

通过中间件使用 HttpContextUse HttpContext from middleware

使用自定义中间件组件时,HttpContext 传递到 InvokeInvokeAsync 方法,在中间件配置后可供访问:

  1. public class MyCustomMiddleware
  2. {
  3. public Task InvokeAsync(HttpContext context)
  4. {
  5. ...
  6. }
  7. }

通过自定义组件使用 HttpContextUse HttpContext from custom components

对于需要访问 HttpContext 的其他框架和自定义组件,建议使用内置的依赖项注入容器来注册依赖项。依赖项注入容器向任意类提供 IHttpContextAccessor,以供类在自己的构造函数中将它声明为依赖项:

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.AddControllersWithViews();
  4. services.AddHttpContextAccessor();
  5. services.AddTransient<IUserRepository, UserRepository>();
  6. }
  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.AddMvc()
  4. .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
  5. services.AddHttpContextAccessor();
  6. services.AddTransient<IUserRepository, UserRepository>();
  7. }

如下示例中:

  • UserRepository 声明自己对 IHttpContextAccessor 的依赖。
  • 当依赖项注入容器解析依赖链并创建 UserRepository 实例时,就会注入依赖项。
  1. public class UserRepository : IUserRepository
  2. {
  3. private readonly IHttpContextAccessor _httpContextAccessor;
  4. public UserRepository(IHttpContextAccessor httpContextAccessor)
  5. {
  6. _httpContextAccessor = httpContextAccessor;
  7. }
  8. public void LogCurrentUser()
  9. {
  10. var username = _httpContextAccessor.HttpContext.User.Identity.Name;
  11. service.LogAccessRequest(username);
  12. }
  13. }

从后台线程访问 HttpContextHttpContext access from a background thread

HttpContext 不是线程安全型。在处理请求之外读取或写入 HttpContext 的属性可能会导致 NullReferenceException

备注

如果应用生成偶发的 NullReferenceException 错误,请评审启动后台处理的部分代码,或者在请求完成后继续处理的部分代码。查找诸如将控制器方法定义为 async void 的错误。

要使用 HttpContext 数据安全地执行后台工作,请执行以下操作:

  • 在请求处理过程中复制所需的数据。
  • 将复制的数据传递给后台任务。

要避免不安全代码,请勿将 HttpContext 传递给执行后台工作的方法。而是传递所需要的数据。在以下示例中,调用 SendEmailCore,开始发送电子邮件。correlationId 传递到 SendEmailCore,而不是 HttpContext代码执行不会等待 SendEmailCore 完成:

  1. public class EmailController : Controller
  2. {
  3. public IActionResult SendEmail(string email)
  4. {
  5. var correlationId = HttpContext.Request.Headers["x-correlation-id"].ToString();
  6. _ = SendEmailCore(correlationId);
  7. return View();
  8. }
  9. private async Task SendEmailCore(string correlationId)
  10. {
  11. ...
  12. }
  13. }