Session null ใน ASP.Net MVC Controller Constructors


89

เหตุใดเซสชันจึงเป็นโมฆะในตัวสร้างของคอนโทรลเลอร์ สามารถเข้าถึงได้จากวิธีการดำเนินการ สันนิษฐานว่าเนื่องจากเฟรมเวิร์กการกำหนดเส้นทาง MVC มีหน้าที่รับผิดชอบในการสร้างคอนโทรลเลอร์ขึ้นมาใหม่จึงไม่ได้สร้างอินสแตนซ์เซสชัน ณ จุดนั้น

ไม่มีใครรู้ว่านี่เป็นเพราะการออกแบบและถ้าเป็นเช่นนั้นทำไม?

[ฉันจัดการเพื่อหลีกเลี่ยงปัญหาโดยใช้ Lazy Loading Pattern แล้ว]

คำตอบ:


80

Andrei ถูกต้อง - เป็นโมฆะเนื่องจากเมื่อทำงานภายใต้กรอบงาน ASP.NET MVC HttpContext (และดังนั้น HttpContext.Session) จะไม่ถูกตั้งค่าเมื่อมีการจัดโครงสร้างคลาสคอนโทรลเลอร์ตามที่คุณคาดไว้ แต่จะตั้งค่า ("injection") ในภายหลัง โดยคลาส ControllerBuilder หากคุณต้องการความเข้าใจที่ดีขึ้นเกี่ยวกับวงจรชีวิตคุณสามารถดึงกรอบงาน ASP.NET MVC (แหล่งที่มาพร้อมใช้งาน) หรืออ้างถึง: หน้านี้

หากคุณต้องการเข้าถึงเซสชันวิธีหนึ่งคือการแทนที่เมธอด "OnActionExecuting" และเข้าถึงที่นั่นเนื่องจากจะพร้อมใช้งานตามเวลานั้น

อย่างไรก็ตามตามที่ Andrei แนะนำหากโค้ดของคุณขึ้นอยู่กับ Session อาจเป็นเรื่องยากที่จะเขียนการทดสอบหน่วยดังนั้นบางทีคุณอาจพิจารณารวม Session ไว้ในคลาสตัวช่วยซึ่งสามารถสลับออกเป็นส่วนอื่นที่ไม่ใช่ - เวอร์ชันเว็บเมื่อทำงานภายใต้การทดสอบหน่วยดังนั้นจึงยกเลิกการเชื่อมต่อคอนโทรลเลอร์ของคุณจากเว็บ


3
ฉันไม่แน่ใจว่านี่เป็นคำสั่งที่ถูกต้องเกี่ยวกับ HttpContext มันสร้างขึ้นจริงตั้งแต่เริ่มต้นของการไหลทั้งหมด คุณสามารถอ่านรายละเอียดเกี่ยวกับโฟลว์โดยละเอียดได้ที่นี่beletsky.net/2011/06/inside-aspnet-mvc-route-to-mvchanlder.html หรือคุณสามารถใช้ตัวสะท้อนแสงและพบว่าตัวเองเมื่อ httpContext ถูกสร้างอินสแตนซ์ - ประมาณบรรทัด 1556 ใน httpruntime .cs
Alexey Shcherbak

@AlexeyShcherbak มันอาจถูกสร้างขึ้นแล้ว - OP คือเกี่ยวกับว่ามีการตั้งค่าในคุณสมบัติ Session ของคอนโทรลเลอร์ MVC หรือไม่ คือ HttpSessionStateBase Session สาธารณะ {get; } บน System.Web.Mvc.Controller นี่คือสิ่งที่แตกต่างกัน
MemeDeveloper

62

นอกเหนือจากคำตอบอื่น ๆ ที่นี่แม้ว่าController.Sessionจะไม่มีการเติมข้อมูลในตัวสร้าง แต่คุณยังสามารถเข้าถึงเซสชันผ่าน:

System.Web.HttpContext.Current.Session

ด้วยข้อแม้มาตรฐานที่อาจลดความสามารถในการทดสอบของคอนโทรลเลอร์ของคุณ


3
ประเภทของคุณสมบัติเซสชันทั้งสองนี้แตกต่างกันซึ่งอาจมีความสำคัญหากคุณต้องการให้การอ้างอิงถึงสถานะเซสชันนั้นเอง
BrianCooksey

@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

คำตอบเก่า แต่อยากจะบอกว่านั่นSystem.Web.HttpContext.Current.Sessionก็nullอยู่ใน VS2019 MVC instanciator
jp2code

คุณสามารถรับ HttpSessionStateBase จาก HttpSessionState ได้โดยการตัดโดยใช้ตัวสร้าง HttpSessionStateWrapper
Fabricio

11

เซสชันจะถูกฉีดเข้าไปในวงจรชีวิตในภายหลัง ทำไมคุณถึงต้องการเซสชันในตัวสร้างต่อไป? หากคุณต้องการ TDD คุณควรรวมเซสชันไว้ในวัตถุจำลอง


1
หากต้องการเพิ่ม Andrei 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

คำตอบนี้อาจเป็นประโยชน์สำหรับบางคน

หากเราแทนที่วิธีการเริ่มต้นเราจะต้องเริ่มต้นคลาสฐานด้วยบริบทคำขอ: ฐานเริ่มต้น (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.