Sesi null di ASP.Net MVC Controller Constructors

89

Mengapa Sesi null di konstruktor Pengontrol? Itu dapat diakses dari metode Tindakan. Agaknya, karena kerangka kerja Perutean MVC bertanggung jawab untuk memperbarui Pengontrol, kerangka tersebut belum (kembali) membuat Sesi pada saat itu.

Adakah yang tahu jika ini memang disengaja dan, jika demikian, mengapa?

[Saya telah berhasil mengatasi masalah ini dengan menggunakan Pola Pemuatan Malas.]

Chris Arnold
sumber

Jawaban:

80

Andrei benar - nilainya null karena saat berjalan di bawah kerangka kerja ASP.NET MVC, HttpContext (dan karenanya HttpContext.Session) tidak disetel saat kelas pengontrol dibuat seperti yang Anda harapkan, tetapi disetel ("diinjeksi") nanti oleh kelas ControllerBuilder. Jika Anda ingin pemahaman yang lebih baik tentang siklus hidup Anda dapat menarik kerangka kerja ASP.NET MVC (sumber tersedia), atau merujuk ke: halaman ini

Jika Anda perlu mengakses Sesi, salah satu cara adalah dengan menimpa metode "OnActionExecuting" dan mengaksesnya di sana, karena akan tersedia pada saat itu.

Namun, seperti yang disarankan Andrei, jika kode Anda bergantung pada Sesi maka akan berpotensi sulit untuk menulis pengujian unit, jadi mungkin Anda dapat mempertimbangkan untuk menggabungkan Sesi dalam kelas pembantu yang kemudian dapat ditukar dengan yang berbeda, non- versi web saat menjalankan pengujian unit, oleh karena itu lepaskan pengontrol Anda dari web.

Andrew W.
sumber
3
Saya tidak yakin ini adalah pernyataan yang tepat tentang HttpContext. Ini sebenarnya dibangun tepat di awal seluruh aliran. Anda dapat membaca sedikit tentang aliran mendetail di sini beletsky.net/2011/06/inside-aspnet-mvc-route-to-mvchanlder.html atau Anda dapat menggunakan reflektor dan menemukan diri Anda ketika httpContext telah dibuat - garis sekitar 1556 di httpruntime .cs.
Alexey Shcherbak
@AlexeyShcherbak Ini mungkin sudah dibangun - OP adalah tentang apakah itu telah ditetapkan pada properti Sesi pengontrol MVC. yaitu Sesi HttpSessionStateBase publik {get; } di System.Web.Mvc.Controller Ini adalah hal yang berbeda.
MemeDeveloper
62

Selain jawaban lain di sini, meskipun Controller.Sessiontidak diisi di konstruktor, Anda masih dapat mengakses sesi melalui:

System.Web.HttpContext.Current.Session

dengan peringatan standar bahwa hal ini berpotensi mengurangi kemampuan pengujian pengontrol Anda.

Mike Chamberlain
sumber
3
Jenis untuk masing-masing dari dua properti sesi ini berbeda, yang mungkin penting jika Anda ingin menyimpan referensi ke status sesi itu sendiri.
BrianCooksey
@ BrianCooksey apa bedanya?
MichaelMao
1
Controller.Session berjenis System.Web.HttpSessionStateBase (lihat msdn.microsoft.com/en-us/library/… ) tetapi System.Web.HttpContext.Current.Session berjenis System.Web.SessionState.HttpSessionState (lihat msdn .microsoft.com / en-us / library /… )
BrianCooksey
Jawaban lama, tetapi ingin mengatakan itu System.Web.HttpContext.Current.Sessionjuga nulldi instanciator VS2019 MVC.
jp2code
Anda bisa mendapatkan HttpSessionStateBase dari HttpSessionState dengan membungkusnya menggunakan konstruktor HttpSessionStateWrapper.
Fabricio
11

Sesi disuntikkan nanti dalam siklus hidup. Mengapa Anda membutuhkan sesi dalam konstruktor? Jika Anda membutuhkannya untuk TDD, Anda harus membungkus sesi menjadi objek yang dapat dipermainkan.

Andrei Rînea
sumber
1
Untuk menambah Andrei Rinea, ini adalah contoh spesifik dari teknik yang disebutkan olehnya: iridescence.no/post/…
murki
4
Saya ingin mengakses Sesi selama konstruktor saya sehingga saya dapat memiliki akses ke informasi sesi yang disimpan sebelumnya. Ya, saya dapat mengganti metode OnActionExecuting, tetapi ini jelas bukan solusi yang elegan.
Chris Arnold
8

Anda dapat mengganti metode Inisialisasi untuk menyetel sesi Anda.

protected override void Initialize(RequestContext requestContext)
Funlover
sumber
2

Jika Anda menggunakan Wadah IoC, coba masukkan dan gunakan HttpSessionStateBasealih - alih Sessionobjek:

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

Jawaban ini mungkin bermanfaat bagi sebagian orang

Jika kita mengganti metode Inisialisasi maka kita harus menginisialisasi kelas dasar dengan konteks permintaan: base.Initialize (requestContext);

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

        }
Prashanth vunnam gcs
sumber
Berguna. Perhatikan bahwa tanda tangan metode protected override void Initialize(System.Web.Routing.RequestContext requestContext).
Martin_W