在 ASP.NET Core 中存取 HttpContext

HttpContext 會封裝關於個別 HTTP 要求和回應的所有資訊。 收到 HTTP 要求時,會初始化 HttpContext 執行個體。 該 HttpContext 執行個體可透過中介軟體和應用程式架構來存取,例如 Web API 控制器、Razor 頁面、SignalR、gRPC 等等。

如需使用 HttpContext 搭配 HTTP 要求和回應的相關資訊,請參閱在 ASP.NET Core 中使用 HttpContext

從 Razor 頁面存取 HttpContext

Razor 頁面 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 中的 Razor 檢視存取 HttpContext

MVC 模式中的 Razor 檢視會透過檢視上的 RazorPage.Context 屬性公開 HttpContext。 以下範例會在內部網路應用程式中使用 Windows 驗證,擷取目前的使用者名稱:

@{
    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 頁面、SignalR、gRPC 等等。

如需使用 HttpContext 搭配 HTTP 要求和回應的相關資訊,請參閱在 ASP.NET Core 中使用 HttpContext

從 Razor 頁面存取 HttpContext

Razor 頁面 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 中的 Razor 檢視存取 HttpContext

MVC 模式中的 Razor 檢視會透過檢視上的 RazorPage.Context 屬性公開 HttpContext。 以下範例會在內部網路應用程式中使用 Windows 驗證,擷取目前的使用者名稱:

@{
    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 其他安全性案例