在 ASP.NET Core 中访问 HttpContext

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

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

从 Razor Pages 访问 HttpContext

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 视图通过视图上的 RazorPage.Context 属性公开 HttpContext。 下面的示例使用 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,请使用传递到 InvokeInvokeAsync 方法的 HttpContext 参数:

public class MyCustomMiddleware
{
    // ...

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

从 SignalR 访问 HttpContext

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

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 数据。 在开始并行任务之前,从上下文中提取所需的数据。

若要避免不安全代码,请勿将 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)
    {
        // ...
    }
}

Razor 组件中的 IHttpContextAccessor/HttpContext(Blazor)

必须避免将 IHttpContextAccessor 与交互式呈现一起使用,因为无有效的 HttpContext 可用。

IHttpContextAccessor 可用于在服务器上静态呈现的组件。 但是,建议尽可能避免这种做法。

HttpContext 只能在常规任务的静态呈现根组件中用作级联参数,这些任务包括检查和修改 App 组件 (Components/App.razor) 中的标头或其他属性。 对于交互式呈现,值始终是 null

[CascadingParameter]
public HttpContext? HttpContext { get; set; }

对于交互式组件中需要 HttpContext 的场景,建议通过服务器的永久性组件状态传输数据。 有关详细信息,请参阅服务器端 ASP.NET Core Blazor 其他安全方案

请勿在服务器端 Blazor 应用的 Razor 组件中直接或间接使用 IHttpContextAccessor/HttpContext Blazor 应用在 ASP.NET Core 管道上下文之外运行。 既不保证 HttpContextIHttpContextAccessor 中可用,也不保证 HttpContext 会保留启动了 Blazor 应用的上下文。

建议在 Blazor 应用的初始呈现期间通过根组件参数将请求状态传递给此应用。 或者,应用可以将数据复制到根组件的初始化生命周期事件中的作用域内服务中,以便在整个应用中使用。 有关详细信息,请参阅服务器端 ASP.NET Core Blazor 其他安全方案

服务器端 Blazor 安全性的一个关键方面是,连接到给定线路的用户可能会在建立 Blazor 线路后的某个时间点得到更新,但 IHttpContextAccessor 不会更新。 有关使用自定义服务应对此情况的详细信息,请参阅服务器端 ASP.NET Core Blazor 其他安全方案

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

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

从 Razor Pages 访问 HttpContext

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 视图通过视图上的 RazorPage.Context 属性公开 HttpContext。 下面的示例使用 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 数据。 在开始并行任务之前,从上下文中提取所需的数据。

若要避免不安全代码,请勿将 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)
    {
        // ...
    }
}

Razor 组件中的 IHttpContextAccessor/HttpContext(Blazor)

必须避免将 IHttpContextAccessor 与交互式呈现一起使用,因为无有效的 HttpContext 可用。

IHttpContextAccessor 可用于在服务器上静态呈现的组件。 但是,建议尽可能避免这种做法。

HttpContext 只能在常规任务的静态呈现根组件中用作级联参数,这些任务包括检查和修改 App 组件 (Components/App.razor) 中的标头或其他属性。 对于交互式呈现,值始终是 null

[CascadingParameter]
public HttpContext? HttpContext { get; set; }

对于交互式组件中需要 HttpContext 的场景,建议通过服务器的永久性组件状态传输数据。 有关详细信息,请参阅服务器端 ASP.NET Core Blazor 其他安全方案

请勿在服务器端 Blazor 应用的 Razor 组件中直接或间接使用 IHttpContextAccessor/HttpContext Blazor 应用在 ASP.NET Core 管道上下文之外运行。 既不保证 HttpContextIHttpContextAccessor 中可用,也不保证 HttpContext 会保留启动了 Blazor 应用的上下文。

建议在 Blazor 应用的初始呈现期间通过根组件参数将请求状态传递给此应用。 或者,应用可以将数据复制到根组件的初始化生命周期事件中的作用域内服务中,以便在整个应用中使用。 有关详细信息,请参阅服务器端 ASP.NET Core Blazor 其他安全方案

服务器端 Blazor 安全性的一个关键方面是,连接到给定线路的用户可能会在建立 Blazor 线路后的某个时间点得到更新,但 IHttpContextAccessor 不会更新。 有关使用自定义服务应对此情况的详细信息,请参阅服务器端 ASP.NET Core Blazor 其他安全方案