ASP.NET Core でのセッションとアプリの状態Session and app state in ASP.NET Core

作成者: Rick AndersonSteve SmithDiana LaRoseLuke LathamBy Rick Anderson, Steve Smith, Diana LaRose, and Luke Latham

HTTP はステートレス プロトコルです。HTTP is a stateless protocol. 手順を追加しないと、HTTP 要求は独立したメッセージであり、ユーザーの値やアプリの状態は保持されません。Without taking additional steps, HTTP requests are independent messages that don't retain user values or app state. この記事では、要求と要求の間でユーザー データとアプリの状態を保持するための複数の方法について説明します。This article describes several approaches to preserve user data and app state between requests.

サンプル コードを表示またはダウンロードします (ダウンロード方法)。View or download sample code (how to download)

状態管理State management

状態は、いくつかの方法で格納することができます。State can be stored using several approaches. このトピックではそれぞれの方法について説明します。Each approach is described later in this topic.

格納の方法Storage approach 格納のメカニズムStorage mechanism
CookieCookies HTTP Cookie (サーバー側アプリのコードを使って格納されるデータを含む場合があります)HTTP cookies (may include data stored using server-side app code)
セッション状態Session state HTTP Cookie とサーバー側アプリ コードHTTP cookies and server-side app code
TempDataTempData HTTP Cookie またはセッション状態HTTP cookies or session state
クエリ文字列Query strings HTTP クエリ文字列HTTP query strings
非表示フィールドHidden fields HTTP フォーム フィールドHTTP form fields
HttpContext.ItemsHttpContext.Items サーバー側アプリ コードServer-side app code
キャッシュCache サーバー側アプリ コードServer-side app code
依存性の注入Dependency Injection サーバー側アプリ コードServer-side app code

クッキーCookies

Cookie は、要求と要求の間でデータを格納します。Cookies store data across requests. Cookie は要求ごとに送信されるために、そのサイズは最小に抑える必要があります。Because cookies are sent with every request, their size should be kept to a minimum. 理想的には、識別子だけを Cookie に格納し、データはアプリで格納します。Ideally, only an identifier should be stored in a cookie with the data stored by the app. ほとんどのブラウザーで Cookie のサイズは 4096 バイトに制限されています。Most browsers restrict cookie size to 4096 bytes. ドメインごとに使用できる Cookie の数も制限されています。Only a limited number of cookies are available for each domain.

Cookie は改ざんされる可能性があるため、アプリで検証する必要があります。Because cookies are subject to tampering, they must be validated by the app. Cookie は、ユーザーが削除でき、クライアント上で期限切れになります。Cookies can be deleted by users and expire on clients. ただし、Cookie は一般に、クライアントでデータを永続化するときに最も持続性のある形式です。However, cookies are generally the most durable form of data persistence on the client.

Cookie は、多くの場合、パーソナル化に利用されます。既知のユーザーのためにコンテンツをカスタマイズします。Cookies are often used for personalization, where content is customized for a known user. ユーザーは識別されるだけであり、ほとんどの場合は認証されません。The user is only identified and not authenticated in most cases. Cookie には、ユーザーの名前、アカウント名、または一意ユーザー ID (GUID など) を格納できます。The cookie can store the user's name, account name, or unique user ID (such as a GUID). その後は、優先される Web サイトの背景色など、ユーザーの個人用設定に Cookie を使ってアクセスできます。You can then use the cookie to access the user's personalized settings, such as their preferred website background color.

Cookie を発行し、プライバシーの問題を扱うときは、欧州連合の一般データ保護規則 (GDPR) に留意してください。Be mindful of the European Union General Data Protection Regulations (GDPR) when issuing cookies and dealing with privacy concerns. 詳細については、「General Data Protection Regulation (GDPR) support in ASP.NET Core」(ASP.NET Core での一般データ保護規則 (GDPR) のサポート) をご覧ください。For more information, see General Data Protection Regulation (GDPR) support in ASP.NET Core.

セッション状態Session state

セッション状態は、ユーザーが Web アプリを参照している期間中ユーザー データを格納するための ASP.NET Core のシナリオです。Session state is an ASP.NET Core scenario for storage of user data while the user browses a web app. セッション状態では、アプリで管理されているストアを使用して、クライアントからの要求間でデータを保持します。Session state uses a store maintained by the app to persist data across requests from a client. セッション データはキャッシュによってバックアップされ、一時的なデータと見なされます。セッション データがなくても、サイトは機能し続けられる必要があります。The session data is backed by a cache and considered ephemeral data—the site should continue to function without the session data. 重要なアプリケーションのデータはユーザー データベースに格納し、パフォーマンスの最適化としてのみセッションでキャッシュする必要があります。Critical application data should be stored in the user database and cached in session only as a performance optimization.

注意

SignalR Hub は HTTP コンテキストとは独立して実行する可能性があるため、SignalR アプリではセッションはサポートされていません。Session isn't supported in SignalR apps because a SignalR Hub may execute independent of an HTTP context. このようなことは、たとえば、長いポーリング要求が HTTP コンテキストの有効期間を超えてハブによって開かれている場合に発生する可能性があります。For example, this can occur when a long polling request is held open by a hub beyond the lifetime of the request's HTTP context.

ASP.NET Core は、セッション ID を含む Cookie をクライアントに提供することで、セッションの状態を維持します。Cookie は要求ごとにサーバーに送信されます。ASP.NET Core maintains session state by providing a cookie to the client that contains a session ID, which is sent to the app with each request. アプリは、セッション ID を使用してセッション データをフェッチします。The app uses the session ID to fetch the session data.

セッション状態は次の動作を示します。Session state exhibits the following behaviors:

  • セッション Cookie はブラウザーに固有であるため、セッションはブラウザー間では共有されません。Because the session cookie is specific to the browser, sessions aren't shared across browsers.
  • セッション Cookie は、ブラウザー セッションが終了するときに削除されます。Session cookies are deleted when the browser session ends.
  • Cookie を受け取り、セッションが期限切れになった場合、同じセッション Cookie を使用する新しいセッションが作成されます。If a cookie is received for an expired session, a new session is created that uses the same session cookie.
  • 空のセッションは保持されません。要求と要求の間でセッションを維持するには、少なくとも 1 つの値をセッションが持っている必要があります。Empty sessions aren't retained—the session must have at least one value set into it to persist the session across requests. セッションが保持されないと、新しい要求ごとに新しいセッション ID が生成されます。When a session isn't retained, a new session ID is generated for each new request.
  • アプリは、最後の要求から限られた時間だけセッションを維持します。The app retains a session for a limited time after the last request. アプリでは、セッション タイムアウトを設定するか、既定値の 20 分を使用します。The app either sets the session timeout or uses the default value of 20 minutes. セッション状態は、特定のセッションに固有であるが、セッション間で永続的に保持する必要のないユーザー データの格納に最適です。Session state is ideal for storing user data that's specific to a particular session but where the data doesn't require permanent storage across sessions.
  • セッション データは、ISession.Clear の実装が呼び出されるか、セッションが期限切れになると、削除されます。Session data is deleted either when the ISession.Clear implementation is called or when the session expires.
  • クライアント ブラウザーが閉じられたこと、またはクライアントでセッション Cookie が削除されるか期限切れになったことを、アプリ コードに通知する既定のメカニズムはありません。There's no default mechanism to inform app code that a client browser has been closed or when the session cookie is deleted or expired on the client.
  • ASP.NET Core MVC と Razor ページのテンプレートには、一般データ保護規制 (GDPR) のサポートが含まれます。The ASP.NET Core MVC and Razor pages templates include support for General Data Protection Regulation (GDPR). セッション状態の Cookie は既定では必須になっていません。このため、サイトの訪問者が追跡を許可しない限り、セッション状態は機能しません。Session state cookies aren't marked essential by default, so session state isn't functional unless tracking is permitted by the site visitor. 詳細については、ASP.NET Core での一般データ保護規則 (GDPR) のサポート を参照してください。For more information, see ASP.NET Core での一般データ保護規則 (GDPR) のサポート.

警告

セッション状態には機密データを保存しないでください。Don't store sensitive data in session state. ユーザーがブラウザーを閉じず、セッション Cookie がクリアされない可能性があります。The user might not close the browser and clear the session cookie. 一部のブラウザーでは、ブラウザー ウィンドウの間で有効なセッションの Cookie が維持されます。Some browsers maintain valid session cookies across browser windows. セッションが 1 人のユーザーに制限されず、次のユーザーが同じセッション Cookie でアプリの閲覧を続けることがあります。A session might not be restricted to a single user—the next user might continue to browse the app with the same session cookie.

メモリ内キャッシュ プロバイダーは、アプリが存在するサーバーのメモリにセッション データを格納します。The in-memory cache provider stores session data in the memory of the server where the app resides. サーバー ファームのシナリオでは次のようになります。In a server farm scenario:

セッション状態を構成するConfigure session state

Microsoft.AspNetCore.App metapackage に含まれる Microsoft.AspNetCore.Session パッケージは、セッション状態を管理するためのミドルウェアを提供します。The Microsoft.AspNetCore.Session package, which is included in the Microsoft.AspNetCore.App metapackage, provides middleware for managing session state. セッション ミドルウェアを有効にするには、Startup に次が含まれている必要があります。To enable the session middleware, Startup must contain:

次のコードでは、IDistributedCache の既定のメモリ内実装でメモリ内セッション プロバイダーを設定する方法を示します。The following code shows how to set up the in-memory session provider with a default in-memory implementation of IDistributedCache:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDistributedMemoryCache();

        services.AddSession(options =>
        {
            // Set a short timeout for easy testing.
            options.IdleTimeout = TimeSpan.FromSeconds(10);
            options.Cookie.HttpOnly = true;
            // Make the session cookie essential
            options.Cookie.IsEssential = true;
        });

        services.AddMvc()
            .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Error");
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseStaticFiles();
        app.UseSession();
        app.UseHttpContextItemsMiddleware();
        app.UseMvc();
    }
}

ミドルウェアの順序が重要です。The order of middleware is important. 上の例では、UseMvc の後で UseSession を呼び出すと、InvalidOperationException 例外が発生します。In the preceding example, an InvalidOperationException exception occurs when UseSession is invoked after UseMvc. 詳細については、ミドルウェアの順序に関するページをご覧ください。For more information, see Middleware Ordering.

HttpContext.Session は、セッション状態を構成した後で使用できます。HttpContext.Session is available after session state is configured.

UseSession を呼び出前に HttpContext.Session にアクセスすることはできません。HttpContext.Session can't be accessed before UseSession has been called.

アプリが応答ストリームへの書き込みを開始した後では、新しいセッション Cookie を含む新しいセッションを作成できません。A new session with a new session cookie can't be created after the app has begun writing to the response stream. 例外は Web サーバー ログに記録され、ブラウザーには表示されません。The exception is recorded in the web server log and not displayed in the browser.

セッション状態を非同期的に読み込むLoad session state asynchronously

TryGetValueSet、または Remove メソッドの前に、ISession.LoadAsync メソッドが明示的に呼び出された場合にのみ、ASP.NET Core の既定のセッション プロバイダーは、基になっている IDistributedCache バッキング ストアからセッション レコードを非同期に読み込みます。The default session provider in ASP.NET Core loads session records from the underlying IDistributedCache backing store asynchronously only if the ISession.LoadAsync method is explicitly called before the TryGetValue, Set, or Remove methods. LoadAsync を最初に呼び出さないと、基になっているセッション レコードは同期的に読み込まれ、パフォーマンスが大幅に低下する可能性があります。If LoadAsync isn't called first, the underlying session record is loaded synchronously, which can incur a performance penalty at scale.

アプリにこのパターンを強制させるには、TryGetValueSet、または Remove の前に LoadAsync メソッドが呼び出されない場合に例外をスローするバージョンで、DistributedSessionStore および DistributedSession の実装をラップします。To have apps enforce this pattern, wrap the DistributedSessionStore and DistributedSession implementations with versions that throw an exception if the LoadAsync method isn't called before TryGetValue, Set, or Remove. ラップしたバージョンをサービス コンテナーに登録します。Register the wrapped versions in the services container.

セッション オプションSession options

セッションの既定値をオーバーライドするには、SessionOptions を使用します。To override session defaults, use SessionOptions.

オプションOption 説明Description
CookieCookie Cookie の作成に使用される設定を決定します。Determines the settings used to create the cookie. Name の既定値は SessionDefaults.CookieName (.AspNetCore.Session) です。Name defaults to SessionDefaults.CookieName (.AspNetCore.Session). Path の既定値は SessionDefaults.CookiePath (/) です。Path defaults to SessionDefaults.CookiePath (/). SameSite の既定値は SameSiteMode.Lax (1) です。SameSite defaults to SameSiteMode.Lax (1). HttpOnly の既定値は true です。HttpOnly defaults to true. IsEssential の既定値は false です。IsEssential defaults to false.
IdleTimeoutIdleTimeout IdleTimeout は、内容を破棄されることなくセッションがアイドル状態になっていることのできる最大時間を示します。The IdleTimeout indicates how long the session can be idle before its contents are abandoned. セッションへのアクセスがあるたびに、タイムアウトはリセットされます。Each session access resets the timeout. この設定はセッションの内容にのみ適用され、Cookie には適用されません。This setting only applies to the content of the session, not the cookie. 既定値は 20 分です。The default is 20 minutes.
IOTimeoutIOTimeout ストアからのセッションの読み込み、またはストアに戻すコミットに対して許容される最大時間です。The maximum amount of time allowed to load a session from the store or to commit it back to the store. この設定は非同期操作にのみ適用できます。This setting may only apply to asynchronous operations. このタイムアウトは、InfiniteTimeSpan を使用して無効にすることができます。This timeout can be disabled using InfiniteTimeSpan. 既定値は 1 分です。The default is 1 minute.

セッションは Cookie を利用し、1 つのブラウザーからの要求を追跡し、識別します。Session uses a cookie to track and identify requests from a single browser. 既定では、この Cookie は .AspNetCore.Session という名前になり、パス / を使用します。By default, this cookie is named .AspNetCore.Session, and it uses a path of /. Cookie の既定値ではドメインが指定されないため、ページのクライアント側スクリプトには使用できません (HttpOnly の既定値が true になるため)。Because the cookie default doesn't specify a domain, it isn't made available to the client-side script on the page (because HttpOnly defaults to true).

Cookie セッションの既定値をオーバーライドするには、SessionOptions を使用します。To override cookie session defaults, use SessionOptions:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<CookiePolicyOptions>(options =>
    {
        options.CheckConsentNeeded = context => true;
        options.MinimumSameSitePolicy = SameSiteMode.None;
    });

    services.AddDistributedMemoryCache();

    services.AddMvc()
        .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

    services.AddSession(options =>
    {
        options.Cookie.Name = ".AdventureWorks.Session";
        options.IdleTimeout = TimeSpan.FromSeconds(10);
        options.Cookie.IsEssential = true;
    });
}

アプリは IdleTimeout プロパティを使用し、サーバーのキャッシュ内の内容が破棄されるまでのセッションのアイドル時間を決定します。The app uses the IdleTimeout property to determine how long a session can be idle before its contents in the server's cache are abandoned. このプロパティは Cookie の有効期限に依存しません。This property is independent of the cookie expiration. 要求がセッション ミドルウェアを通過するたびにタイムアウトがリセットされます。Each request that passes through the Session Middleware resets the timeout.

セッション状態は "ロックなし" です。Session state is non-locking. 2 つの要求がセッションの内容を同時に変更しようとした場合、最後の要求が最初の要求をオーバーライドします。If two requests simultaneously attempt to modify the contents of a session, the last request overrides the first. Session一貫性のあるセッションとして実装されます。つまり、コンテンツは全部まとめて保管されます。Session is implemented as a coherent session, which means that all the contents are stored together. 2 つの要求が異なるセッション値を変更しようとしたとき、最後の要求が最初の要求によって行われたセッションの変更をオーバーライドすることがあります。When two requests seek to modify different session values, the last request may override session changes made by the first.

セッション値の設定および取得Set and get Session values

セッション状態には、Razor Pages の PageModel クラスから、または MVC の Controller クラスの HttpContext.Session でアクセスします。Session state is accessed from a Razor Pages PageModel class or MVC Controller class with HttpContext.Session. このプロパティは ISession 実装です。This property is an ISession implementation.

ISession の実装では、整数値や文字列値を設定および取得するための複数の拡張メソッドが提供されています。The ISession implementation provides several extension methods to set and retrieve integer and string values. Microsoft.AspNetCore.Http.Extensions パッケージがプロジェクトによって参照されている場合、拡張メソッドは Microsoft.AspNetCore.Http 名前空間内にあります (拡張メソッドにアクセスするには、using Microsoft.AspNetCore.Http; ステートメントを追加します)。The extension methods are in the Microsoft.AspNetCore.Http namespace (add a using Microsoft.AspNetCore.Http; statement to gain access to the extension methods) when the Microsoft.AspNetCore.Http.Extensions package is referenced by the project. どちらのパッケージも、Microsoft.AspNetCore.App メタパッケージに含まれます。Both packages are included in the Microsoft.AspNetCore.App metapackage.

ISession 拡張メソッド:ISession extension methods:

次の例では、IndexModel.SessionKeyName キー (サンプル アプリ内の _Name) のセッション値を Razor Pages ページで取得します。The following example retrieves the session value for the IndexModel.SessionKeyName key (_Name in the sample app) in a Razor Pages page:

@page
@using Microsoft.AspNetCore.Http
@model IndexModel

...

Name: @HttpContext.Session.GetString(IndexModel.SessionKeyName)

次の例では、整数および文字列を設定および取得する方法を示します。The following example shows how to set and get an integer and a string:

public class IndexModel : PageModel
{
    public const string SessionKeyName = "_Name";
    public const string SessionKeyAge = "_Age";
    const string SessionKeyTime = "_Time";

    public string SessionInfo_Name { get; private set; }
    public string SessionInfo_Age { get; private set; }
    public string SessionInfo_CurrentTime { get; private set; }
    public string SessionInfo_SessionTime { get; private set; }
    public string SessionInfo_MiddlewareValue { get; private set; }

    public void OnGet()
    {
        // Requires: using Microsoft.AspNetCore.Http;
        if (string.IsNullOrEmpty(HttpContext.Session.GetString(SessionKeyName)))
        {
            HttpContext.Session.SetString(SessionKeyName, "The Doctor");
            HttpContext.Session.SetInt32(SessionKeyAge, 773);
        }

        var name = HttpContext.Session.GetString(SessionKeyName);
        var age = HttpContext.Session.GetInt32(SessionKeyAge);

分散キャッシュのシナリオを有効にするには、メモリ内キャッシュを使用する場合であっても、すべてのセッション データをシリアル化する必要があります。All session data must be serialized to enable a distributed cache scenario, even when using the in-memory cache. 最小限の文字列と数値のシリアライザーが提供されています (ISession のメソッドおよびの拡張メソッドをご覧ください)。Minimal string and number serializers are provided (see the methods and extension methods of ISession). 複合型は、JSON などの別のメカニズムを使ってユーザーがシリアル化する必要があります。Complex types must be serialized by the user using another mechanism, such as JSON.

シリアル化可能なオブジェクトを設定および取得するには、次の拡張メソッドを追加します。Add the following extension methods to set and get serializable objects:

public static class SessionExtensions
{
    public static void Set<T>(this ISession session, string key, T value)
    {
        session.SetString(key, JsonConvert.SerializeObject(value));
    }

    public static T Get<T>(this ISession session, string key)
    {
        var value = session.GetString(key);

        return value == null ? default(T) : 
            JsonConvert.DeserializeObject<T>(value);
    }
}

次の例では、シリアル化可能オブジェクトを拡張メソッドで設定および取得する方法を示します。The following example shows how to set and get a serializable object with the extension methods:

// Requires you add the Set and Get extension method mentioned in the topic.
if (HttpContext.Session.Get<DateTime>(SessionKeyTime) == default(DateTime))
{
    HttpContext.Session.Set<DateTime>(SessionKeyTime, currentTime);
}

TempDataTempData

ASP.NET Core によって、Razor Pages TempData または Controller TempData が発行されます。ASP.NET Core exposes the Razor Pages TempData or Controller TempData. このプロパティには、別の要求で読み取られるまでデータが格納されます。This property stores data until it's read in another request. Keep (String) メソッドと Peek (String) メソッドを使用すると、要求の最後に削除せずにデータを調べることができます。Keep(String) and Peek(string) methods can be used to examine the data without deletion at the end of the request. Keep() によって、リテンション期間についてディクショナリ内のすべての項目がマークされます。Keep() marks all items in the dictionary for retention. TempData は特に、複数の要求にデータが必要な場合のリダイレクトに役立ちます。TempData is particularly useful for redirection when data is required for more than a single request. TempData は、TempData プロバイダーによって Cookie またはセッション状態を使用して実装されます。TempData is implemented by TempData providers using either cookies or session state.

TempData のサンプルTempData samples

顧客を作成する次のページについて考えてみましょう。Consider the following page that creates a customer:

public class CreateModel : PageModel
{
    private readonly RazorPagesContactsContext _context;

    public CreateModel(RazorPagesContactsContext context)
    {
        _context = context;
    }

    public IActionResult OnGet()
    {
        return Page();
    }

    [TempData]
    public string Message { get; set; }

    [BindProperty]
    public Customer Customer { get; set; }

    public async Task<IActionResult> OnPostAsync()
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }

        _context.Customer.Add(Customer);
        await _context.SaveChangesAsync();
        Message = $"Customer {Customer.Name} added";

        return RedirectToPage("./IndexPeek");
    }
}

次のページに TempData["Message"] が表示されます。The following page displays TempData["Message"]:

@page
@model IndexModel

<h1>Peek Contacts</h1>

@{
    if (TempData.Peek("Message") != null)
    {
        <h3>Message: @TempData.Peek("Message")</h3>
    }
}

@*Content removed for brevity.*@

前のマークアップでは、Peek が使用されているため、要求の最後に TempData["Message"] が削除されませんIn the preceding markup, at the end of the request, TempData["Message"] is not deleted because Peek is used. ページを更新すると TempData["Message"] が表示されます。Refreshing the page displays TempData["Message"].

次のマークアップは前のコードと似ていますが、Keep を使用して要求の最後にデータを保存しています。The following markup is similar to the preceding code, but uses Keep to preserve the data at the end of the request:

@page
@model IndexModel

<h1>Contacts Keep</h1>

@{
    if (TempData["Message"] != null)
    {
        <h3>Message: @TempData["Message"]</h3>
    }
    TempData.Keep("Message");
}

@*Content removed for brevity.*@

Indexpeek ページと IndexKeep ページ間を移動しても TempData["Message"] は削除されません。Navigating between the IndexPeek and IndexKeep pages won't delete TempData["Message"].

次のコードでは TempData["Message"] が表示されますが、要求の最後に TempData["Message"] が削除されます。The following code displays TempData["Message"], but at the end of the request, TempData["Message"] is deleted:

@page
@model IndexModel

<h1>Index no Keep or Peek</h1>

@{
    if (TempData["Message"] != null)
    {
        <h3>Message: @TempData["Message"]</h3>
    }
}

@*Content removed for brevity.*@

TempData プロバイダーTempData providers

Cookie に TempData を格納するには、Cookie ベースの TempData プロバイダーが既定で使われます。The cookie-based TempData provider is used by default to store TempData in cookies.

Cookie データは IDataProtector を使用して暗号化され、Base64UrlTextEncoder でエンコードされ、チャンクされます。The cookie data is encrypted using IDataProtector, encoded with Base64UrlTextEncoder, then chunked. Cookie はチャンクされるため、ASP.NET Core 1.x の 1 Cookie のサイズ上限は適用されません。Because the cookie is chunked, the single cookie size limit found in ASP.NET Core 1.x doesn't apply. 暗号化されているデータを圧縮すると、CRIME 攻撃や BREACH 攻撃など、セキュリティ上の問題を起す可能性があるため、Cookie データは圧縮されません。The cookie data isn't compressed because compressing encrypted data can lead to security problems such as the CRIME and BREACH attacks. Cookie ベース TempData プロバイダーの詳細については、「CookieTempDataProvider」を参照してください。For more information on the cookie-based TempData provider, see CookieTempDataProvider.

TempData プロバイダーを選択するChoose a TempData provider

TempData プロバイダーを選択するときの考慮事項:Choosing a TempData provider involves several considerations, such as:

  1. アプリは既にセッション状態を使っているかどうか。Does the app already use session state? 使っている場合、(データのサイズを除き) セッション状態 TempData プロバイダーがそのアプリにコストを追加することはありません。If so, using the session state TempData provider has no additional cost to the app (aside from the size of the data).
  2. アプリでは、比較的少量のデータに対して (最大 500 バイト) TempData がわずかばかり使用されているか。Does the app use TempData only sparingly for relatively small amounts of data (up to 500 bytes)? 該当する場合、Cookie TempData プロバイダーは TempData を送信する要求ごとに少額のコストを追加します。If so, the cookie TempData provider adds a small cost to each request that carries TempData. 該当しない場合、セッション状態 TempData プロバイダーは便利かもしれません。TempData が尽きるまで、要求のたびに大量のデータをラウンドトリップすることが回避されます。If not, the session state TempData provider can be beneficial to avoid round-tripping a large amount of data in each request until the TempData is consumed.
  3. アプリは複数サーバーのサーバー ファームで実行しているか。Does the app run in a server farm on multiple servers? そうである場合は、データ保護の外部で Cookie TempData プロバイダーを使用するために、追加の構成は必要ありません (ASP.NET Core データ保護 およびキー ストレージ プロバイダーに関する記事を参照)。If so, there's no additional configuration required to use the cookie TempData provider outside of Data Protection (see ASP.NET Core データ保護 and Key storage providers).

注意

ほとんどの Web クライアント (Web ブラウザーなど) は、各 Cookie の最大サイズ、Cookie の合計数、または両方に上限を課します。Most web clients (such as web browsers) enforce limits on the maximum size of each cookie, the total number of cookies, or both. Cookie TempData プロバイダーを使用するとき、アプリでそれらの上限が超えないことを確認してください。When using the cookie TempData provider, verify the app won't exceed these limits. データの合計サイズを考慮してください。Consider the total size of the data. 暗号化とチャンクによる Cookie のサイズの増加を考慮してください。Account for increases in cookie size due to encryption and chunking.

TempData プロバイダーを構成するConfigure the TempData provider

Cookie ベース TempData プロバイダーは既定で有効になります。The cookie-based TempData provider is enabled by default.

セッション ベースの TempData プロバイダーを有効にするには、AddSessionStateTempDataProvider 拡張メソッドを使います。To enable the session-based TempData provider, use the AddSessionStateTempDataProvider extension method:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<CookiePolicyOptions>(options =>
    {
        options.CheckConsentNeeded = context => true;
        options.MinimumSameSitePolicy = SameSiteMode.None;
    });

    services.AddMvc()
        .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
        .AddSessionStateTempDataProvider();

    services.AddSession();
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseDatabaseErrorPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseCookiePolicy();
    app.UseSession();
    app.UseMvc();
}

ミドルウェアの順序が重要です。The order of middleware is important. 上の例では、UseMvc の後で UseSession を呼び出すと、InvalidOperationException 例外が発生します。In the preceding example, an InvalidOperationException exception occurs when UseSession is invoked after UseMvc. 詳細については、ミドルウェアの順序に関するページをご覧ください。For more information, see Middleware Ordering.

重要

.NET Framework が対象で、セッション ベースの TempData プロバイダーを使う場合は、Microsoft.AspNetCore.Session パッケージをプロジェクトに追加します。If targeting .NET Framework and using the session-based TempData provider, add the Microsoft.AspNetCore.Session package to the project.

クエリ文字列Query strings

限られた量のデータを要求間で渡すことができます。新しい要求のクエリ文字列にそれを追加します。A limited amount of data can be passed from one request to another by adding it to the new request's query string. これは、リンクと埋め込まれた状態がメールまたはソーシャル ネットワークを通して共有されるよう、永久的に状態をキャプチャするのに役立ちます。This is useful for capturing state in a persistent manner that allows links with embedded state to be shared through email or social networks. URL クエリ文字列はパブリックであるため、機密データにはクエリ文字列を使わないでください。Because URL query strings are public, never use query strings for sensitive data.

意図しない共有が発生するだけでなく、クエリ文字列にデータを含めると、クロスサイト リクエスト フォージェリ (CSRF) 攻撃の機会を与えてしまいます。認証中、ユーザーをだまして悪意のあるサイトに誘導します。In addition to unintended sharing, including data in query strings can create opportunities for Cross-Site Request Forgery (CSRF) attacks, which can trick users into visiting malicious sites while authenticated. 攻撃者はアプリからユーザー データを盗んだり、ユーザーになりすまして悪意のある行為を行ったりできます。Attackers can then steal user data from the app or take malicious actions on behalf of the user. 保存されるアプリまたはセッション状態は CSRF 攻撃を防ぐ必要があります。Any preserved app or session state must protect against CSRF attacks. 詳細については、「Prevent Cross-Site Request Forgery (XSRF/CSRF) attacks」(クロスサイト リクエスト フォージェリ (XSRF/CSRF) 攻撃の防止) を参照してください。For more information, see Prevent Cross-Site Request Forgery (XSRF/CSRF) attacks.

非表示フィールドHidden fields

データは非表示フォーム フィールドに保存したり、次の要求で転記したりできます。Data can be saved in hidden form fields and posted back on the next request. 複数ページ フォームでは、これは一般的です。This is common in multi-page forms. クライアントがデータを改ざんする可能性があるため、アプリで非表示フィールドに格納されているデータを常に再検証する必要があります。Because the client can potentially tamper with the data, the app must always revalidate the data stored in hidden fields.

HttpContext.ItemsHttpContext.Items

1 つの要求を処理している間データを格納するには、HttpContext.Items コレクションを使います。The HttpContext.Items collection is used to store data while processing a single request. 要求が処理された後、コレクションの内容は破棄されます。The collection's contents are discarded after a request is processed. Items コレクションは、コンポーネントまたはミドルウェアが要求の間の異なる時点で動作し、パラメーターを受け渡す直接的な方法がない場合に、コンポーネントとミドルウェアが通信できるようにするためによく使われます。The Items collection is often used to allow components or middleware to communicate when they operate at different points in time during a request and have no direct way to pass parameters.

次の例では、ミドルウェアにより isVerifiedItems コレクションに追加されます。In the following example, middleware adds isVerified to the Items collection.

app.Use(async (context, next) =>
{
    // perform some verification
    context.Items["isVerified"] = true;
    await next.Invoke();
});

後のパイプラインで、別のミドルウェアが isVerified の値にアクセスできます。Later in the pipeline, another middleware can access the value of isVerified:

app.Run(async (context) =>
{
    await context.Response.WriteAsync($"Verified: {context.Items["isVerified"]}");
});

1 つのアプリでのみ使用されるミドルウェアの場合、string キーが許容されます。For middleware that's only used by a single app, string keys are acceptable. アプリのインスタンス間で共有されるミドルウェアでは、キーの競合を避けるため、一意のオブジェクト キーを使う必要があります。Middleware shared between app instances should use unique object keys to avoid key collisions. 次の例では、ミドルウェア クラスで定義されている一意のオブジェクト キーを使用する方法を示します。The following example shows how to use a unique object key defined in a middleware class:

public class HttpContextItemsMiddleware
{
    private readonly RequestDelegate _next;
    public static readonly object HttpContextItemsMiddlewareKey = new Object();

    public HttpContextItemsMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext httpContext)
    {
        httpContext.Items[HttpContextItemsMiddlewareKey] = "K-9";

        await _next(httpContext);
    }
}

public static class HttpContextItemsMiddlewareExtensions
{
    public static IApplicationBuilder 
        UseHttpContextItemsMiddleware(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<HttpContextItemsMiddleware>();
    }
}

その他のコードは、ミドルウェア クラスで公開されるキーを利用し、HttpContext.Items に格納されている値にアクセスできます。Other code can access the value stored in HttpContext.Items using the key exposed by the middleware class:

HttpContext.Items
    .TryGetValue(HttpContextItemsMiddleware.HttpContextItemsMiddlewareKey, 
        out var middlewareSetValue);
SessionInfo_MiddlewareValue = 
    middlewareSetValue?.ToString() ?? "Middleware value not set!";

この方法には、コード内でキーの文字列を使用する必要がないという利点もあります。This approach also has the advantage of eliminating the use of key strings in the code.

キャッシュCache

キャッシュは、データを保存し、取得する効率的な方法です。Caching is an efficient way to store and retrieve data. アプリでは、キャッシュされた項目の有効期間を制御できます。The app can control the lifetime of cached items.

キャッシュされたデータは、特定の要求、ユーザー、またはセッションに関連付けられていません。Cached data isn't associated with a specific request, user, or session. 他のユーザーの要求によって取得される可能性があるので、ユーザー固有データをキャッシュしないように注意してください。Be careful not to cache user-specific data that may be retrieved by other users' requests.

詳細については、ASP.NET Core での応答のキャッシュ を参照してください。For more information, see ASP.NET Core での応答のキャッシュ.

依存関係の挿入Dependency Injection

依存関係の注入を利用し、すべてのユーザーがデータを利用できるようにします。Use Dependency Injection to make data available to all users:

  1. データを含むサービスを定義します。Define a service containing the data. たとえば、MyAppData という名前のクラスを定義します。For example, a class named MyAppData is defined:

    public class MyAppData
    {
        // Declare properties and methods
    }
    
  2. サービス クラスを Startup.ConfigureServices に追加します。Add the service class to Startup.ConfigureServices:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<MyAppData>();
    }
    
  3. データ サービス クラスを使用します。Consume the data service class:

    public class IndexModel : PageModel
    {
        public IndexModel(MyAppData myService)
        {
            // Do something with the service
            //    Examples: Read data, store in a field or property
        }
    }
    

一般的なエラーCommon errors

  • "'Microsoft.AspNetCore.Session.DistributedSessionStore' を起動しようとしましたが、型 'Microsoft.Extensions.Caching.Distributed.IDistributedCache' のサービスを解決できません。""Unable to resolve service for type 'Microsoft.Extensions.Caching.Distributed.IDistributedCache' while attempting to activate 'Microsoft.AspNetCore.Session.DistributedSessionStore'."

    これは通常、少なくとも 1 つの IDistributedCache 実装で構成に失敗したことで発生します。This is usually caused by failing to configure at least one IDistributedCache implementation. 詳細については、次のトピックを参照してください。 ASP.NET Core での分散キャッシュ および ASP.NET Core 内のメモリ内のキャッシュFor more information, see ASP.NET Core での分散キャッシュ and ASP.NET Core 内のメモリ内のキャッシュ.

  • セッション ミドルウェアがセッションを永続化できなかった場合 (バッキング ストアを利用できない場合など)、ミドルウェアは例外をログに記録し、要求は普通に続行されます。In the event that the session middleware fails to persist a session (for example, if the backing store isn't available), the middleware logs the exception and the request continues normally. これにより、予期しない動作が発生します。This leads to unpredictable behavior.

    たとえば、ユーザーがセッションでショッピング カートを格納します。For example, a user stores a shopping cart in session. ユーザーはアイテムをカートに追加しますが、コミットが失敗します。The user adds an item to the cart but the commit fails. アプリはこの失敗を認識しないので、アイテムがカートに追加されたことをユーザーに伝えますが、これは正しくありません。The app doesn't know about the failure so it reports to the user that the item was added to their cart, which isn't true.

    エラーを確認するための推奨される方法は、アプリがセッションへの書き込みを終了したら、アプリ コードから await feature.Session.CommitAsync(); を呼び出すことです。The recommended approach to check for errors is to call await feature.Session.CommitAsync(); from app code when the app is done writing to the session. バッキング ストアが利用できない場合、CommitAsync は例外をスローします。CommitAsync throws an exception if the backing store is unavailable. CommitAsync が失敗した場合、アプリは例外を処理できます。If CommitAsync fails, the app can process the exception. LoadAsync は、データ ストアが利用できない場合に同じ条件で例外をスローします。LoadAsync throws under the same conditions where the data store is unavailable.

SignalR とセッション状態SignalR and session state

SignalR アプリでは、セッション状態を使用して情報を格納することはできません。SignalR apps should not use session state to store information. SignalR アプリは、ハブの Context.Items に接続ごとの状態を格納できます。SignalR apps can store per connection state in Context.Items in the hub.

その他の技術情報Additional resources

Web ファームでの ASP.NET Core のホスト