質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
86.12%
セッション

Sessionはクライアントがサーバに送ったすべてのリクエストのことを指します。

ASP.NET

ASP.NETは動的なWebサイトやWebアプリケーション、そしてWebサービスを構築出来るようにする為、Microsoftによって開発されたウェブアプリケーション開発フレームワークです。

解決済

セッションタイムアウトの処理方法

WhiteHorse
WhiteHorse

総合スコア1

セッション

Sessionはクライアントがサーバに送ったすべてのリクエストのことを指します。

ASP.NET

ASP.NETは動的なWebサイトやWebアプリケーション、そしてWebサービスを構築出来るようにする為、Microsoftによって開発されたウェブアプリケーション開発フレームワークです。

1回答

0グッド

2クリップ

9720閲覧

投稿2020/08/20 06:27

編集2020/08/21 04:41

前提・実現したいこと

ASP.NET MVC5を使用してWebシステムを作成しています。質問はセッションタイムアウトの処理方法です。
セッション管理はInProcモードです。
セッションタイムアウトはデフォルトの20分です。
セッションタイムアウトのチェックはアクションフィルター(OnActionExecuting)を使用しています。アクションフィルターは、セッションタイムアウトが発生すると、強制的にセッションタイムアウト画面に遷移します。このため、セッションタイムアウトが発生すると、URLに示すControllerのアクションメソッドには制御は移りません。

発生している問題・エラーメッセージ

月に一回程度の頻度で、URLに示すControllerのアクションメソッドで、Sessionオブジェクトが未定義のNull参照エラーが発生しています。
Sessionオブジェクトはログイン成功時に必ず設定しているため、このオブジェクトがNullになるのはセッションタイムアウト時のみです。

エラーメッセージ
Object reference not set to an instance of an object.

該当のソースコード

アクションフィルタのコードです。

public

1 { 2 public override void OnActionExecuting(ActionExecutingContext filterContext) 3 { 4 base.OnActionExecuting(filterContext); 5 6 HttpContext context = HttpContext.Current; 7 8 // セッション管理は有効か? 9 if (context.Session != null) 10 { 11 // 新しいセッションIdが生成されたか? 12 if (context.Session.IsNewSession) 13 { 14 // 新しいクッキーが存在するなら、セッションタイムアウトと見なす 15 string sessionCookie = context.Request.Headers["Cookie"]; 16 if ((null != sessionCookie) && (sessionCookie.IndexOf("ASP.NET_SessionId") >= 0)) 17 { 18 // セッションタイムアウト画面へリダイレクトする 19 filterContext.Result=new RedirectResult("~/Account/SessionTimeOut"); 20 } 21 } 22 } 23 24 } 25 }

### エラーが発生したコード

public ActionResult RegisterCommon(DateTime displayDay) { // 担当を自由に変更できる期間は2週間前まで var timeLimitDay = displayDay.AddDays(-14); // 本日 var today = DateTime.Now.ToUniversalTime().AddHours(9).Date; // ユーザのIDを読み取る var membershipId = (string)Session["MEMBERSHIP_ID"]; // 代行処理の場合、代行される人のIDを設定 if ((String)Session["SUBSTITUTED_ID"] != null) { membershipId = (string)Session["SUBSTITUTED_ID"]; } // 事務局か? var isAdministrator = false; if ((bool)Session["ADMINISTRATOR"]) <<<--ここで例外が発生 isAdministrator = true; // 指定日の担当登録を全て読み取る var tantoItemsInDay = new List<Tanto>(); tantoItemsInDay = db.TantoTbl .Where(item => item.Date == displayDay) .ToList(); ・・・・・・・ return View("Register", model); }

試したこと

エラーが発生しているControllerアクションメソッドでセッションタイムアウトを発生させて確認しましたが、正しくセッションタイムアウトを認識し、Null参照エラーは発生しません。
疑わしいのは、セッションタイムアウト判定アルゴリズムと睨んでいるのですが、ASP.NETにおけるセッションタイムアウト処理の情報が少なく、悩んでいます。
なお、使用しているセッションタイムアウト判定アルゴリズムはstackOverflowに掲載されていたコードを使っています。

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

以下のような質問にはグッドを送りましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

グッドが多くついた質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

気になる質問をクリップする

クリップした質問は、後からいつでもマイページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

下記のような質問は推奨されていません。

  • 間違っている
  • 質問になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

適切な質問に修正を依頼しましょう。

SurferOnWww

2020/08/20 07:38

コードは ``` と ``` で囲ってください(``` はバッククォート 3 つ)。インデントされて読みやすくなりますので。インデントされてないコードは質問者さん自身も読む気がしないのでは?
SurferOnWww

2020/08/20 07:40

> 使用しているセッションタイムアウト判定アルゴリズムはstackOverflowに掲載されていたコードを使っています。 質問欄を編集してそれへのリンクを張ってください。
SurferOnWww

2020/08/20 14:03

参考にした StackOverFlow のサイトの URL は、その文字列を記載するだけではなく、クリックすれば遷移できるようリンクを張ってください。 > 月に一回程度の頻度で、URLに示すControllerのアクションメソッドで、Sessionオブジェクトが未定義のNull参照エラーが発生しています。 それはコードのどの行で発生するのですか? そもそも、「月に一回程度の頻度」ではログを取るとかしないとどこでどうなっているか分からないと思うのですが、どのようにして調べたのですか? InProc モードになっていて、ワーカープロセスのリサイクルの影響を受けているということはないですか? セッションタイムアウトで影響を受けるのはサーバー側に保持されたセッションデータのみのはずで、タイムアウトしたか否かを調べるにはデータが消去されたか否かを調べるということになると思いますが、それはやってないですよね? そもそも、セッションタイムアウトを判定したい理由な何なのですか?
WhiteHorse

2020/08/21 00:20

ご指摘ありがとうございます。以下に回答します。 > それはコードのどの行で発生するのですか? そもそも、「月に一回程度の頻度」ではログを取るとかしないとどこでどうなっているか分からないと思うのですが、どのようにして調べたのですか? ->> MVCの例外フィルターで例外ログを取得しています。取得したスタックトレースよりエラー箇所を特定化しました。 > セッションタイムアウトで影響を受けるのはサーバー側に保持されたセッションデータのみのはずで、タイムアウトしたか否かを調べるにはデータが消去されたか否かを調べるということになると思いますが、それはやってないですよね? ->> ログを取得する時にSessionオブジェクトもログするように変更しました、これによりSessionオブジェクトが消去されていることを確認しています。 > InProc モードになっていて、ワーカープロセスのリサイクルの影響を受けているということはないですか? ->> InProcモードで動作しています。IISのワーカープロセスがSessionオブジェクトを消去しても、Session情報は初期化されるものと考えていましたが、甘かったのでしょうか。Azure Redisに変更する予定ですので、これを優先するようにします。 > セッションタイムアウトを判定したい理由な何なのですか? ->> Sessionオブジェクトでユーザー情報をを引き継いでいるためです。
SurferOnWww

2020/08/21 01:13

私の質問の「それはコードのどの行で発生するのですか?」に答えていただいていないようですが、質問欄を編集して追加情報として提供願います。 また、InProc モードであることも質問欄を編集して書いてください。 > Sessionオブジェクトでユーザー情報を引き継いでいるためです。 ユーザー認証は独自実装なのですか? ASP.NET Identity などフレームワークで用意されている認証システムは使えないのですか? 時々そういうのがあるのを知らないで独自実装している人をここ Teratail でもお見掛けするので聞いてます。フレームワークで用意されている認証システムは十分承知で、使えない事情があるということでしょうか?
WhiteHorse

2020/08/21 04:45

ユーザー認証はASP.NET Identityを使用しています。
SurferOnWww

2020/08/21 04:59

> ユーザー認証はASP.NET Identityを使用しています。 そうであれば Session を使わなくても済むと思うのですが? > Sessionオブジェクトでユーザー情報を引き継いでいるためです。 とのことですが、その「ユーザー情報」とは何ですか? プロファイル情報として追加してはいかが? 具体例は以下の記事を見てください。 プロファイル情報の追加 (.NET 版) http://surferonwww.info/BlogEngine/post/2020/05/26/add-profile-information-aspnet-mvc5-dotnet-framework-version.aspx また、そもそも、セッションの「タイムアウト」状態と ASP.NET Identity による認証の「ログアウト」状態は違うということは認識されてますか? ASP.NET Identity による認証の「ログアウト」状態とは認証チケットを持っていない、もしくは認証チケットは持っていても期限切れという状態です。セッションがタイムアウトしていても認証チケットは有効と言うことは当然あります。その逆もあります。
WhiteHorse

2020/08/21 06:31

> Session を使わなくても済むと思うのですが? ->> Session管理があるのならば、それを使ったインプリにより経験を増やすのも意義があると思います。 > セッションの「タイムアウト」状態と ASP.NET Identity による認証の「ログアウト」状態は違うということは認識されてますか? ->> もちろん認識しています。
SurferOnWww

2020/08/21 06:54

> Session管理があるのならば、それを使ったインプリにより経験を増やすのも意義があると思います。 質問に追加した「エラーが発生したコード」を見ると、ユーザーの認証・承認の話で、認証を受けた特定のユーザーをアドミとして承認するという話のように思えますが、そうであれば ASP.NET Identity のロール管理で行うべきで、そこにセッション管理の経験を増やしても意義はないと思いますけど。適材適所というものがあるわけですから。 ASP.NET Identity のロール管理 (MVC) http://surferonwww.info/BlogEngine/post/2017/11/02/role-management-on-aspnet-identity-for-mvc-application.aspx ・・・と言っていても聞く耳持たないような感じですので、とりあえず今回のセッションの話のレスを回答欄に書いておきます。

回答1

1

ベストアンサー

問題は 2 つあって、

(1) アクションフィルターが 100% 完全にセッション情報の消失を捉えきれてない、それなのに、

(2) 質問に追記した「エラーが発生したコード」で null チェックができていない

・・・と言うことだと思います。

(1) アクションフィルター

まず勘違いされていると思われる点を指摘しておきます。

// 新しいセッションIdが生成されたか?
if (context.Session.IsNewSession)

セッション情報を使う(Session["data"] = "xxx"; というようなコードがある)場合は ASP.NET_SessionId という名前で中身は固定のセッションクッキーがブラウザを閉じるまで使われ続けます。「新しいセッションIdが生成」ということは起こりません。

セッションタイムアウトすると HttpSesseionState.Abandon メソッドが呼び出されますが、その次の要求の処置の時に限り IsNewSession が true になります。

なので、普通は、IsNewSession が true で sessionCookie.IndexOf("ASP.NET_SessionId") >= 0 も true であれば、その直前の要求を処置する際セッションタイムアウトしたと見なしてもよさそうです。

でも、質問には、

月に一回程度の頻度で

と書いてありましたので、月一回程度の頻度で普通ではない&想定外のことが起こったのだろうと思います。

例えば、質問のコメント欄で書きましたが InProc モードでは、ワーカープロセスのリサイクルでセッション情報は失われます。アンチウィルスソフトには web.config や Global.asax に変更されたという印をつけるものがあるそうで、そうなった場合もセッション情報は失われます。

他にもあるかもしれません。それらすべての問題を見つけて対処し 100% フィルタリングできるようにするのは難しそうです。

(2) エラーが発生したコード

フィルタリングをすり抜けることを想定して質問に追加した「エラーが発生したコード」でチェックしていると思いますが、そこがきちんとできてないです。

ASP.NET のセッションを使う場合、普通以下のような null チェックとキャストを行います。

var preferredColor = ""; var data = Session["message"]; if (data != null) { preferredColor = (string)data; }

質問者さんのコードで、

var membershipId = (string)Session["MEMBERSHIP_ID"];

とか、

if ((String)Session["SUBSTITUTED_ID"] != null)

がエラーにならなかったのは、セッションデータが消失して null でも string 型にはキャストできるからでしょう。

if ((bool)Session["ADMINISTRATOR"])

で NullReferenceException になったのは null は bool 型にはキャストできないからでしょう。

以下、余計なお世話かもしれませんが・・・

ユーザー認証はASP.NET Identityを使用しています。

ということであればセッションなどは使わないで解決する方法を考えることをお勧めします。

質問に追加した「エラーが発生したコード」を見ると、ユーザーの認証・承認の話で、認証を受けた特定のユーザーをアドミとして承認するという話のように思えますが、そうであれば ASP.NET Identity のロール管理で行うべきです。

ASP.NET Identity のロール管理 (MVC)
http://surferonwww.info/BlogEngine/post/2017/11/02/role-management-on-aspnet-identity-for-mvc-application.aspx

ASP.NET Identity による認証の「ログアウト」状態とは認証チケットを持っていない、もしくは認証チケットは持っていても期限切れという状態です。セッションがタイムアウトしていても認証チケットは有効と言うことは当然あります。その逆もあります。

そこでまた問題が出そうな気がします。

単なる勉強のためということでも、適材適所というものがあるわけですから、認証・承認にセッション管理の経験を増やしても意義はないと思います。

投稿2020/08/21 07:35

SurferOnWww

総合スコア17328

WhiteHorse👍を押しています

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

回答へのコメント

WhiteHorse

2020/08/21 11:11

有難うございます。 セッションタイムアウトが発生したことを確実に把握できるアルゴリズムを知りたかったのですが、無理ということですね。提案されたインプリをを検討してみます。
SurferOnWww

2020/08/21 11:47 編集

> セッションタイムアウトが発生したことを確実に把握できるアルゴリズムを知りたかったのですが、無理ということですね。 無理ではないと思います。タイムアウトすればセッション情報は削除されますので、先に設定したセッション情報が null か否かで 100% 間違いなく判定できると思いますが? 問題はどのタイミングで判定して、どのように判定結果を生かすことができるかということだと思います。 アクションフィルターなど使わなくても、「エラーが発生したコード」で null か否かを判定して対処できるのであれば、それでもいいのでは?

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
86.12%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問

同じタグがついた質問を見る

セッション

Sessionはクライアントがサーバに送ったすべてのリクエストのことを指します。

ASP.NET

ASP.NETは動的なWebサイトやWebアプリケーション、そしてWebサービスを構築出来るようにする為、Microsoftによって開発されたウェブアプリケーション開発フレームワークです。