Skip to content

MS_ASPNETCoreSession

nishi_74322014 edited this page Aug 21, 2026 · 1 revision

ASP.NET CoreのSession利用方法

概要

少し難しい。

補足(何が「難しい」のか): ASP.NET Session と比べて、
前提が根本的に変わっているためである。

ASP.NET (System.Web) ASP.NET Core
既定で有効か 有効(何もしなくても使える) 無効(明示的に有効化が必要)
格納できる型 任意のオブジェクトシリアライズ byte[]string のみ
保存先の抽象 SessionState プロバイダー IDistributedCache
既定の保存先 InProc(プロセス内) メモリ内AddDistributedMemoryCache
IsNewSession あり 無い
Cookie 名 ASP.NET_SessionId 既定 .AspNetCore.Session(変更可)

「難しい」の実体は、

  1. 明示的に組み立てる必要がある(自動では何も付かない)
  2. オブジェクトをそのまま入れられない
  3. 複数台構成では 分散キャッシュ
    データ保護 の両方を揃えないと動かない

の 3 点に整理できる。特に 3 が見落とされやすい。

詳細

インターフェイス

文字列のみ格納可

文字列しか格納できなくなったので、複雑なオブジェクトは JSON に変換する。

補足(正確には byte[] が基本): ISession が持つのは
Set(string, byte[]) / TryGetValue(string, out byte[]) で、
SetString / GetString / SetInt32 / GetInt32
その上の拡張メソッドである。

// 標準で用意されているのはこれだけ
HttpContext.Session.SetString("name", "yamada");
HttpContext.Session.SetInt32("age", 30);
var name = HttpContext.Session.GetString("name");

// オブジェクトは自分で JSON にする
public static void SetObject<T>(this ISession s, string key, T value)
    => s.SetString(key, JsonSerializer.Serialize(value));

public static T? GetObject<T>(this ISession s, string key)
    => s.GetString(key) is { } v ? JsonSerializer.Deserialize<T>(v) : default;

この「不便さ」は意図的である。
ASP.NET の BinaryFormatter によるセッション格納は、
.NET の Serialize で述べた通り
脆弱性(CWE-502)と版の非互換を抱えていた。
明示的に JSON へ変換させることで、
何が保存されるかを開発者が把握できるようにしている。

設計上の指針: そもそも
セッションに大きなオブジェクトを入れない
(ID だけ入れて、実体は DB / キャッシュから引く)のが望ましい。

IsNewSession プロパティ

補足(IsAvailable との違い): ISession には
IsAvailable というプロパティがあるが、これは
「セッションが読み込み済みで使える状態か」を表すもので、
「新規セッションか」ではない

原文の回避策(判定用のキーを自分で入れておく)は現在も有効で、
定石と言ってよい。

if (HttpContext.Session.GetString("__init") is null)
{
    HttpContext.Session.SetString("__init", "1");   // 新規セッション
    // 初期化処理
}

注意: ASP.NET Core のセッションは
何か書き込むまで Cookie が発行されない(遅延生成)。
このため「新規かどうか」を判定するには、
上記のように何かを書き込む必要がある。

構成

Startup

  • Configure メソッド
// Sessionを使用する。
app.UseSession(new SessionOptions()
{
  IdleTimeout = TimeSpan.FromMinutes(30), // ここで調整
  IOTimeout = TimeSpan.FromSeconds(30),
  Cookie = new CookieBuilder()
  {
    Expiration = TimeSpan.FromDays(1), // 効かない
    HttpOnly = true,
    Name = "mvc_session",
    Path = "/",
    SameSite = SameSiteMode.Strict,
    SecurePolicy = CookieSecurePolicy.SameAsRequest
  }
});
  • ConfigureServices メソッド
// Sessionを使用する。
services.AddSession();

補足(Expiration が「効かない」理由): 原文のコメントは正しい観測で、
仕様として無視される

セッション Cookie は ブラウザを閉じたら消える
(=有効期限を持たない)Cookie
として発行される決まりであり、
CookieBuilder.Expiration を設定しても
SessionMiddleware はそれを使わない。

セッションの寿命 = IdleTimeout(サーバ側の保持期間)
Cookie の寿命    = ブラウザ セッション(明示的な期限なし)

有効期限を延ばしたい場合は IdleTimeout を調整する
(これがサーバ側でセッション データを保持する時間)。

補足(.NET 6 以降の書き方/最新化): Startup.cs
最小ホスティング モデルにより既定で生成されなくなった
ASP.NET Core における DI 参照)。
現在は Program.cs に書く。

var builder = WebApplication.CreateBuilder(args);

// ① セッションの保存先(既定はメモリ内。複数台なら分散キャッシュに差し替える)
builder.Services.AddDistributedMemoryCache();

// ② セッション自体
builder.Services.AddSession(options =>
{
    options.IdleTimeout = TimeSpan.FromMinutes(30);
    options.IOTimeout   = TimeSpan.FromSeconds(30);
    options.Cookie.Name        = "mvc_session";
    options.Cookie.HttpOnly    = true;
    options.Cookie.IsEssential = true;   // 同意バナーの有無に関わらず発行する
    options.Cookie.SameSite    = SameSiteMode.Strict;
    options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
});

var app = builder.Build();

app.UseRouting();
app.UseSession();          // ← UseRouting の後、UseEndpoints/Map より前
app.UseAuthorization();
app.MapControllers();
app.Run();

順序が重要である。UseSession()
UseRouting() の後、エンドポイント実行より前に置く
(前後を誤ると HttpContext.Session が使えず例外になる)。

IsEssential = true も実務上重要で、
GDPR 同意機能(CookiePolicyOptions)を有効にしている場合、
これを立てないと同意前はセッション Cookie が発行されない

StateServer モード

補足(複数台構成で必要になるもの): ASP.NET Session
StateServer / SQL Server モードに相当するのが
分散キャッシュ だが、
それだけでは足りない点に注意する。

【複数台で セッションを共有するために必要なもの】

  ① IDistributedCache の共有        … Redis / SQL Server
       → セッションの中身を共有する

  ② データ保護キーの共有            … [データ保護](MS_ASPNETCoreDataProtection)
       → Cookie の暗号化・復号キーを揃える
       → 揃っていないと、別サーバに飛んだ瞬間に Cookie を復号できず
         セッションが「新規」になる

  ③ ApplicationName の統一          … SetApplicationName()

② の見落としが最頻の事故で、
「Redis を入れたのにセッションが切れる」という症状になる
ASP.NET Coreのデータ保護)。

参考

Microsoft Learn


Tags: 移行, プログラミング, .NET開発, .NET Core, ASP.NET, ASP.NET MVC

NetDevInfraWiki

マイクロソフト系技術情報 Wiki
Open 棟梁 Wiki

(未着手)

開発基盤部会 Wiki

移行管理: DONETODO

Clone this wiki locally