在 ASP.NET Core 中访问 HttpContext

注意

此版本不是本文的最新版本。 有关当前版本,请参阅本文.NET 9 版本。

警告

此版本的 ASP.NET Core 不再受支持。 有关详细信息,请参阅 .NET 和 .NET Core 支持策略。 有关当前版本,请参阅本文.NET 9 版本。

重要

此信息与预发布产品相关,相应产品在商业发布之前可能会进行重大修改。 Microsoft 对此处提供的信息不提供任何明示或暗示的保证。

有关当前版本,请参阅本文.NET 9 版本。

HttpContext 封装了有关个别 HTTP 请求和响应的所有信息。 收到 HTTP 请求时,HttpContext 实例会进行初始化。 HttpContext 实例可通过中间件和应用框架(如 Web API 控制器、Razor Pages、SignalR、gRPC 等)访问。

有关将 HttpContext 与 HTTP 请求和响应一起使用的信息,请参阅在 ASP.NET Core 中使用 HttpContext

HttpContext Pages 访问 Razor

Razor Pages PageModel 公开 PageModel.HttpContext 属性:

public class IndexModel : PageModel
{
    public void OnGet()
    {
        var message = HttpContext.Request.PathBase;

        // ...
    }
}

相同的属性可在相应的 Razor 页面视图中使用:

@page
@model IndexModel

@{
    var message = HttpContext.Request.PathBase;

    // ...
}

从 MVC 的 HttpContext 视图中访问 Razor

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

@{
    var username = Context.User.Identity.Name;

    // ...
}

通过控制器访问 HttpContext

控制器公开 ControllerBase.HttpContext 属性:

public class HomeController : Controller
{
    public IActionResult About()
    {
        var pathBase = HttpContext.Request.PathBase;

        // ...

        return View();
    }
}

通过最小 API 访问 HttpContext

若要通过最小 API 使用 HttpContext,请添加 HttpContext 参数:

app.MapGet("/", (HttpContext context) => context.Response.WriteAsync("Hello World"));

通过中间件访问 HttpContext

若要通过自定义中间件组件使用 HttpContext,请使用传递到 HttpContextInvoke 方法的 InvokeAsync 参数:

public class MyCustomMiddleware
{
    // ...

    public async Task InvokeAsync(HttpContext context)
    {
        // ...
    }
}

HttpContext 访问 SignalR

若要通过 HttpContext 使用 SignalR,请对 GetHttpContext 调用 Hub.Context 方法:

public class MyHub : Hub
{
    public async Task SendMessage()
    {
        var httpContext = Context.GetHttpContext();

        // ...
    }
}

通过 gRPC 方法访问 HttpContext

若要通过 gRPC 方法使用 HttpContext,请参阅在 gRPC 方法中解析 HttpContext

通过自定义组件访问 HttpContext

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

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();
builder.Services.AddHttpContextAccessor();
builder.Services.AddTransient<IUserRepository, UserRepository>();

如下示例中:

  • UserRepository 声明自己对 IHttpContextAccessor 的依赖。
  • 当 DI 容器解析依赖链并创建 UserRepository 实例时,将提供依赖项。
public class UserRepository : IUserRepository
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public UserRepository(IHttpContextAccessor httpContextAccessor) =>
        _httpContextAccessor = httpContextAccessor;

    public void LogCurrentUser()
    {
        var username = _httpContextAccessor.HttpContext.User.Identity.Name;

        // ...
    }
}

从后台线程访问 HttpContext

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

注意

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

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

  • 在请求处理过程中复制所需的数据。
  • 将复制的数据传递给后台任务。
  • 请勿在并行任务中引用 数据。 在开始并行任务之前,从上下文中提取所需的数据。

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

public class EmailController : Controller
{
    public IActionResult SendEmail(string email)
    {
        var correlationId = HttpContext.Request.Headers["X-Correlation-Id"].ToString();

        _ = SendEmailCoreAsync(correlationId);

        return View();
    }

    private async Task SendEmailCoreAsync(string correlationId)
    {
        // ...
    }
}

IHttpContextAccessor 组件中的 /HttpContextRazor(Blazor)

有关详细信息,请参阅 ASP.NET Core Blazor 应用中IHttpContextAccessor/HttpContext。

HttpContext 封装了有关个别 HTTP 请求和响应的所有信息。 收到 HTTP 请求时,HttpContext 实例会进行初始化。 HttpContext 实例可通过中间件和应用框架(如 Web API 控制器、Razor Pages、SignalR、gRPC 等)访问。

有关将 HttpContext 与 HTTP 请求和响应一起使用的信息,请参阅在 ASP.NET Core 中使用 HttpContext

HttpContext Pages 访问 Razor

Razor Pages PageModel 公开 PageModel.HttpContext 属性:

public class IndexModel : PageModel
{
    public void OnGet()
    {
        var message = HttpContext.Request.PathBase;

        // ...
    }
}

相同的属性可在相应的 Razor 页面视图中使用:

@page
@model IndexModel

@{
    var message = HttpContext.Request.PathBase;

    // ...
}

从 MVC 的 HttpContext 视图中访问 Razor

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

@{
    var username = Context.User.Identity.Name;

    // ...
}

通过控制器访问 HttpContext

控制器公开 ControllerBase.HttpContext 属性:

public class HomeController : Controller
{
    public IActionResult About()
    {
        var pathBase = HttpContext.Request.PathBase;

        // ...

        return View();
    }
}

通过中间件访问 HttpContext

使用自定义中间件组件时,HttpContext 传递到 InvokeInvokeAsync 方法:

public class MyCustomMiddleware
{
    public Task InvokeAsync(HttpContext context)
    {
        // ...
    }
}

通过自定义组件访问 HttpContext

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

public void ConfigureServices(IServiceCollection services)
{
     services.AddControllersWithViews();
     services.AddHttpContextAccessor();
     services.AddTransient<IUserRepository, UserRepository>();
}

如下示例中:

  • UserRepository 声明自己对 IHttpContextAccessor 的依赖。
  • 当 DI 容器解析依赖链并创建 UserRepository 实例时,将提供依赖项。
public class UserRepository : IUserRepository
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public UserRepository(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    public void LogCurrentUser()
    {
        var username = _httpContextAccessor.HttpContext.User.Identity.Name;
        service.LogAccessRequest(username);
    }
}

从后台线程访问 HttpContext

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

注意

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

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

  • 在请求处理过程中复制所需的数据。
  • 将复制的数据传递给后台任务。
  • 请勿在并行任务中引用 数据。 在开始并行任务之前,从上下文中提取所需的数据。

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

public class EmailController : Controller
{
    public IActionResult SendEmail(string email)
    {
        var correlationId = HttpContext.Request.Headers["x-correlation-id"].ToString();

        _ = SendEmailCore(correlationId);

        return View();
    }

    private async Task SendEmailCore(string correlationId)
    {
        // ...
    }
}

IHttpContextAccessor 组件中的 /HttpContextRazor(Blazor)

有关详细信息,请参阅 ASP.NET Core Blazor 应用中IHttpContextAccessor/HttpContext。