ASP.Net MVCコントローラーコンストラクターのセッションnull


88

コントローラのコンストラクタでSessionがnullになるのはなぜですか?アクションメソッドからアクセスできます。おそらく、MVCルーティングフレームワークはコントローラーの更新を担当しているため、その時点ではセッションを(再)インスタンス化していません。

これが仕様によるものであるかどうか、そうであればなぜですか?

[遅延読み込みパターンを使用して問題を回避することができました。]

回答:


78

Andreiは正解です。ASP.NETMVCフレームワークで実行している場合、コントローラークラスが予想どおりに構築されたときにHttpContext(およびHttpContext.Session)が設定されないため、これはnullですが、後で設定(「挿入」)されます。 ControllerBuilderクラスによって。ライフサイクルをよりよく理解したい場合は、ASP.NET MVCフレームワーク(ソースは利用可能です)をプルダウンするか、またはこのページを参照してください。

セッションにアクセスする必要がある場合、「OnActionExecuting」メソッドをオーバーライドしてそこにアクセスする方法があります。その時点で利用可能になるためです。

ただし、Andreiが示唆しているように、コードがセッションに依存している場合は、単体テストを作成するのが難しい可能性があるため、おそらく、セッションをヘルパークラスにラップして、別の非ユニットテストで実行しているときのWebバージョン。したがって、コントローラーをWebから切り離します。


2
これがHttpContextについての適切な記述であるとは思いません。実際には、フロー全体の開始時に正しく構築されました。ここで詳細なフローについて少し読むことができますbeletsky.net/2011/06/inside-aspnet-mvc-route-to-mvchanlder.html またはリフレクターを使用してhttpContextがインスタンス化されたときに自分自身を見つけることができます-httpruntimeの1556行目.cs。
Alexey Shcherbak

@AlexeyShcherbak既に構築されている可能性があります-OPは、MVCコントローラーのSessionプロパティで設定されているかどうかについてです。つまり、パブリックHttpSessionStateBase Session {get; } on System.Web.Mvc.Controllerこれらは異なるものです。
MemeDeveloper

61

ここでの他の回答に加えて、Controller.Sessionはコンストラクタに入力されていませんが、次の方法でセッションにアクセスできます。

System.Web.HttpContext.Current.Session

これにより、コントローラーのテスト性が低下する可能性があるという標準的な警告があります。


3
これらの2つのセッションプロパティのタイプはそれぞれ異なります。セッション状態自体への参照を保持する場合は、これが問題になる場合があります。
BrianCooksey 2013年

@BrianCooksey何が違うの?
MichaelMao

1
Controller.SessionのタイプはSystem.Web.HttpSessionStateBase(msdn.microsoft.com/en-us/library/…を参照)ですが、System.Web.HttpContext.Current.SessionのタイプはSystem.Web.SessionState.HttpSessionState(msdnを参照)です。 .microsoft.com / en-us / library /…
BrianCooksey '26

10

セッションはライフサイクルの後半で挿入されます。なぜとにかくコンストラクタでセッションが必要なのですか?TDDで必要な場合は、セッションをモック可能なオブジェクトにラップする必要があります。


1
アンドレイRineaに追加するには、これは彼が言及した技術の具体的な例である:iridescence.no/post/...
murki

4
以前に保存されたセッション情報にアクセスできるように、コンストラクターの間にセッションにアクセスしたいと思います。はい、OnActionExecutingメソッドをオーバーライドできますが、これは確かに洗練されたソリューションではありません。
Chris Arnold、

8

Initializeメソッドをオーバーライドして、セッションを設定できます。

protected override void Initialize(RequestContext requestContext)

2

IoCコンテナを使用している場合HttpSessionStateBaseは、Sessionオブジェクトの代わりにを挿入して使用してみてください。

private static Container defaultContainer()
{
    return new Container(ioc =>
    {
        // session manager setup
        ioc.For<HttpSessionStateBase>()
           .Use(ctx => new HttpSessionStateWrapper(HttpContext.Current.Session)); 
    });
}

2

この答えは一部の人にとって役立つかもしれません

Initializeメソッドをオーバーライドする場合は、リクエストコンテキストで基本クラスを初期化する必要があります。base.Initialize(requestContext);

protected override void Initialize(RequestContext requestContext)
        {
            base.Initialize(requestContext);
           

        }

有用。メソッドの署名に注意してくださいprotected override void Initialize(System.Web.Routing.RequestContext requestContext)
Martin_W
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.