Phiên rỗng trong ASP.Net MVC Controller Constructors


88

Tại sao Session rỗng trong các hàm tạo của Bộ điều khiển? Nó có thể được truy cập từ các phương thức Hành động. Có lẽ, bởi vì khuôn khổ Định tuyến MVC chịu trách nhiệm tạo mới Bộ điều khiển, nên nó chưa (lại) khởi tạo Phiên tại thời điểm đó.

Có ai biết nếu điều này là do thiết kế và, nếu có, tại sao?

[Tôi đã tìm cách khắc phục sự cố bằng cách sử dụng Dạng tải lười biếng.]

Câu trả lời:


79

Andrei nói đúng - nó là null vì khi chạy trong khung ASP.NET MVC, HttpContext (và do đó HttpContext.Session) không được đặt khi lớp điều khiển được cấu trúc như bạn có thể mong đợi, nhưng nó được đặt ("tiêm") sau đó bởi lớp ControllerBuilder. Nếu bạn muốn hiểu rõ hơn về vòng đời, bạn có thể kéo xuống khung ASP.NET MVC (nguồn có sẵn) hoặc tham khảo: trang này

Nếu bạn cần truy cập Session thì một cách sẽ là ghi đè phương thức "OnActionExecuting" và truy cập nó ở đó, vì nó sẽ khả dụng vào thời điểm đó.

Tuy nhiên, như Andrei đang đề xuất, nếu mã của bạn phụ thuộc vào Phiên thì có thể khó viết các bài kiểm tra đơn vị, vì vậy có lẽ bạn có thể cân nhắc gói Phiên trong một lớp trợ giúp mà sau đó có thể được hoán đổi cho một lớp khác, không phiên bản web khi chạy trong các bài kiểm tra đơn vị, do đó, loại bỏ khớp nối bộ điều khiển của bạn khỏi web.


3
Tôi không chắc đây là tuyên bố thích hợp về HttpContext. Nó thực sự được xây dựng ngay khi bắt đầu toàn bộ dòng chảy. Bạn có thể đọc một chút về quy trình chi tiết tại đây beletsky.net/2011/06/inside-aspnet-mvc-route-to-mvchanlder.html hoặc bạn có thể sử dụng phản xạ và tự tìm khi httpContext đã được khởi tạo - nó ở khoảng dòng 1556 trong httpruntime .cs.
Alexey Shcherbak

@AlexeyShcherbak Nó có thể đã được xây dựng - OP là về việc liệu nó đã được đặt trên thuộc tính Session của bộ điều khiển MVC hay chưa. tức là public HttpSessionStateBase Session {get; } trên System.Web.Mvc.Controller Đây là những thứ khác nhau.
MemeDeveloper 27/01/16

61

Ngoài các câu trả lời khác ở đây, mặc dù Controller.Sessionkhông được điền vào hàm tạo, bạn vẫn có thể truy cập phiên thông qua:

System.Web.HttpContext.Current.Session

với cảnh báo tiêu chuẩn rằng điều này có thể làm giảm khả năng kiểm tra của bộ điều khiển của bạn.


3
Loại cho mỗi thuộc tính phiên này là khác nhau, điều này có thể quan trọng nếu bạn định giữ một tham chiếu đến chính trạng thái phiên.
BrianCooksey

@BrianCooksey có gì khác biệt?
MichaelMao

1
Controller.Session thuộc loại System.Web.HttpSessionStateBase (xem msdn.microsoft.com/en-us/library/… ) nhưng System.Web.HttpContext.Current.Session thuộc loại System.Web.SessionState.HttpSessionState (xem msdn .microsoft.com / en-us / thư viện / ... )
BrianCooksey

Câu trả lời cũ, nhưng muốn nói rằng System.Web.HttpContext.Current.Sessioncũng có nulltrong trình cài đặt MVC VS2019.
jp2code

11

Phiên được đưa vào sau đó trong vòng đời. Tại sao bạn vẫn cần phiên trong hàm khởi tạo? Nếu bạn cần nó cho TDD, bạn nên gói phiên thành một đối tượng có thể giả lập.


1
Để thêm vào Andrei Rinea, đây là một ví dụ cụ thể của kỹ thuật được đề cập bởi ông: iridescence.no/post/...
murki

4
Tôi muốn truy cập Phiên trong các hàm tạo của mình để tôi có thể truy cập vào thông tin phiên được lưu trữ trước đó. Có, tôi có thể ghi đè phương thức OnActionExecuting, nhưng đây chắc chắn không phải là một giải pháp thanh lịch.
Chris Arnold

8

Bạn có thể ghi đè phương thức Khởi tạo để đặt phiên của mình.

protected override void Initialize(RequestContext requestContext)

2

Nếu bạn đang sử dụng IoC Container, hãy thử chèn và sử dụng HttpSessionStateBasethay vì Sessionđối tượng:

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

2

Câu trả lời này có thể hữu ích cho một số người

Nếu chúng ta ghi đè phương thức Khởi tạo thì chúng ta phải khởi tạo lớp cơ sở với ngữ cảnh yêu cầu: base.Initialize (requestContext);

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

        }

Hữu ích. Lưu ý rằng chữ ký phương pháp protected override void Initialize(System.Web.Routing.RequestContext requestContext).
Martin_W
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.