ASP.NET Core の HttpContext にアクセスする

HttpContext を指定すると、個々の HTTP 要求と応答に関するすべての情報がカプセル化されます。 HttpContext インスタンスは、HTTP 要求の受信時に初期化されます。 HttpContext インスタンスには、ミドルウェアや Web API コントローラー、Razor Pages、SignalR、gRPC などのアプリ フレームワークからアクセスできます。

HTTP の要求と応答での HttpContext の使用について詳しくは、「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 の 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();
    }
}

Minimal API から HttpContext にアクセスする

最小限の API から HttpContext を使うには、HttpContext パラメーターを追加します。

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

ミドルウェアから HttpContext にアクセスする

カスタム ミドルウェア コンポーネントから HttpContext を使うには、Invoke または InvokeAsync メソッドに渡された 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>();

次に例を示します。

  • UserRepositoryIHttpContextAccessor に対する依存関係を宣言します。
  • 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 になることがあります。

Note

アプリで NullReferenceException エラーが散発的に生成される場合、コードの中で、バックグラウンド処理を開始する部分や要求完了後に処理を続行する部分を見直してください。 コントローラー メソッドを async void として定義するなどの間違いを探します。

HttpContext データでバックグラウンド作業を安全に行うには:

  • 要求処理中に必要なデータをコピーします。
  • コピーしたデータをバックグラウンド タスクに渡します。
  • 並列タスクで HttpContext データを参照 "しないで" ください。 必要なデータは、並列タスクを開始する前にコンテキストから抽出してください。

アンセーフ コードを避けるために、バックグラウンド処理を行わないメソッドには HttpContext を決して渡さないでください。 代わりに必要なデータを渡してください。 次の例では、電子メールの送信を開始するために SendEmailSendEmailCoreAsync を呼びします。 X-Correlation-Id ヘッダーの値は、HttpContext ではなく SendEmailCoreAsync に渡されます。 コードの実行では、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)

有効な HttpContext が使用できないため、対話型レンダリングでは IHttpContextAccessor を避ける必要があります。

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 パイプラインのコンテキストの外部で実行されます。 HttpContext は、IHttpContextAccessor 内で使用できるとは限りません。また、HttpContext は、Blazor アプリを開始したコンテキストが保持されることも保証されません。

アプリの初期レンダリング中にルート コンポーネント パラメーターを使って要求の状態を Blazor アプリに渡すことをお勧めします。 または、ルート コンポーネントの初期化ライフサイクル イベントにおいてアプリでスコープ サービスにデータをコピーすることで、アプリ全体で使用することもできます。 詳細については、「サーバーサイド ASP.NET Core Blazor のセキュリティに関するその他のシナリオ」を参照してください。

サーバー側 Blazor のセキュリティでの重要な側面は、特定の回線に接続されているユーザーは Blazor 回線が確立された後のある時点で更新される可能性がありますが、IHttpContextAccessor更新されないということです。 カスタム サービスでこの状況に対処する方法の詳細については、「サーバーサイド ASP.NET Core Blazor のセキュリティに関するその他のシナリオ」を参照してください。

HttpContext を指定すると、個々の HTTP 要求と応答に関するすべての情報がカプセル化されます。 HttpContext インスタンスは、HTTP 要求の受信時に初期化されます。 HttpContext インスタンスには、ミドルウェアや Web API コントローラー、Razor Pages、SignalR、gRPC などのアプリ フレームワークからアクセスできます。

HTTP の要求と応答での HttpContext の使用について詳しくは、「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 の 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 にアクセスする

カスタム ミドルウェア コンポーネントを使用する場合、HttpContextInvoke メソッドまたは InvokeAsync メソッドに渡されます。

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>();
}

次に例を示します。

  • UserRepositoryIHttpContextAccessor に対する依存関係を宣言します。
  • 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 になることがあります。

Note

アプリで NullReferenceException エラーが散発的に生成される場合、コードの中で、バックグラウンド処理を開始する部分や要求完了後に処理を続行する部分を見直してください。 コントローラー メソッドを async void として定義するなどの間違いを探します。

HttpContext データでバックグラウンド作業を安全に行うには:

  • 要求処理中に必要なデータをコピーします。
  • コピーしたデータをバックグラウンド タスクに渡します。
  • 並列タスクで HttpContext データを参照 "しないで" ください。 必要なデータは、並列タスクを開始する前にコンテキストから抽出してください。

アンセーフ コードを避けるために、バックグラウンド処理を行わないメソッドには HttpContext を決して渡さないでください。 代わりに必要なデータを渡してください。 次の例では、電子メールの送信を開始するために SendEmailCore が呼び出されます。 correlationId は、HttpContext ではなく SendEmailCore に渡されます。 コードの実行では、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)

有効な HttpContext が使用できないため、対話型レンダリングでは IHttpContextAccessor を避ける必要があります。

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 パイプラインのコンテキストの外部で実行されます。 HttpContext は、IHttpContextAccessor 内で使用できるとは限りません。また、HttpContext は、Blazor アプリを開始したコンテキストが保持されることも保証されません。

アプリの初期レンダリング中にルート コンポーネント パラメーターを使って要求の状態を Blazor アプリに渡すことをお勧めします。 または、ルート コンポーネントの初期化ライフサイクル イベントにおいてアプリでスコープ サービスにデータをコピーすることで、アプリ全体で使用することもできます。 詳細については、「サーバーサイド ASP.NET Core Blazor のセキュリティに関するその他のシナリオ」を参照してください。

サーバー側 Blazor のセキュリティでの重要な側面は、特定の回線に接続されているユーザーは Blazor 回線が確立された後のある時点で更新される可能性がありますが、IHttpContextAccessor更新されないということです。 カスタム サービスでこの状況に対処する方法の詳細については、「サーバーサイド ASP.NET Core Blazor のセキュリティに関するその他のシナリオ」を参照してください。