Biến phiên trong ASP.NET MVC


169

Tôi đang viết một ứng dụng web cho phép người dùng duyệt đến nhiều trang web trong trang web theo yêu cầu nhất định. Tất cả thông tin mà người dùng nhập vào sẽ được lưu trữ trong một đối tượng mà tôi đã tạo. Vấn đề là tôi cần truy cập đối tượng này từ bất kỳ phần nào của trang web và tôi thực sự không biết cách tốt nhất để thực hiện điều này. Tôi biết rằng một giải pháp là sử dụng các biến phiên nhưng tôi không biết cách sử dụng chúng trong asp .net MVC. Và tôi sẽ khai báo một biến phiên ở đâu? Còn cách nào khác không?


3
Bạn đang trộn các khái niệm Trang web và Ứng dụng Web ... chúng không giống nhau.
adripanico

1
Nghe có vẻ như cần một cơ sở dữ liệu
Coops

Câu trả lời:


123

Tôi nghĩ bạn sẽ muốn nghĩ xem liệu mọi thứ có thực sự thuộc về trạng thái phiên hay không. Đây là điều tôi thấy mình đang làm mọi lúc và sau đó là một cách tiếp cận được đánh máy mạnh mẽ cho toàn bộ nhưng bạn nên cẩn thận khi đặt mọi thứ vào bối cảnh phiên. Không phải mọi thứ nên ở đó chỉ vì nó thuộc về một số người dùng.

trong global.asax kết nối sự kiện OnSessionStart

void OnSessionStart(...)
{
    HttpContext.Current.Session.Add("__MySessionObject", new MySessionObject());
}

Từ bất cứ nơi nào trong mã nơi thuộc tính httpContext.C hiện tại! = Null bạn có thể truy xuất lại đối tượng đó. Tôi làm điều này với một phương pháp mở rộng.

public static MySessionObject GetMySessionObject(this HttpContext current)
{
    return current != null ? (MySessionObject)current.Session["__MySessionObject"] : null;
}

Bằng cách này bạn có thể trong mã

void OnLoad(...)
{
    var sessionObj = HttpContext.Current.GetMySessionObject();
    // do something with 'sessionObj'
}

32
Nếu ASP MVC đang được sử dụng thì tốt nhất là không sử dụng đối tượng Phiên thực tế từ HttpContext.Cản.Session.Session mà sử dụng httpSessionStateWrapper & HttpSessionStateBase mới từ System.Web.Abstrilities.dll sau đó sử dụng Factory hoặc DI để lấy Phiên.
Paul

6
Làm thế nào để bạn chỉ định một cái gì đó cho biến phiên? (trái ngược với việc chỉ truy cập)
raklos

31
Đối với những người đang cố gắng tìm hiểu sự kiện "OnSessionStart" là gì và bạn "kết nối" nó như thế nào, hãy xem stackoverflow.com/questions/1531125/NH
Cephron

5
@Paul Bạn có thể cung cấp một ví dụ? Tôi dường như không thể tìm thấy bất kỳ ví dụ nào về việc sử dụng HttpSessionStateWrapper.
Joseph Woodward

4
@AjayKelkar chủ đề bình luận này gợi ý: "Nếu ASP MVC đang được sử dụng sau đó nó là một lợi thế không sử dụng đối tượng Session thực tế từ HttpContext.Current.Session nhưng để sử dụng mới HttpSessionStateWrapper & HttpSessionStateBase" mà gợi ý câu trả lời của bạn nó không tốt hơn
Coops

48

Câu trả lời ở đây là chính xác, tuy nhiên tôi đã vật lộn để thực hiện nó trong một ứng dụng ASP.NET MVC 3. Tôi muốn truy cập một đối tượng Phiên trong bộ điều khiển và không thể hiểu tại sao tôi cứ tiếp tục "Trường hợp không được đặt thành một trường hợp của lỗi Đối tượng". Điều tôi nhận thấy là trong một bộ điều khiển khi tôi cố gắng truy cập phiên bằng cách làm như sau, tôi tiếp tục gặp lỗi đó. Điều này là do thực tế rằng điều này.HttpContext là một phần của đối tượng Trình điều khiển.

this.Session["blah"]
// or
this.HttpContext.Session["blah"]

Tuy nhiên, điều tôi muốn là HTTPContext là một phần của không gian tên System.Web vì đây là câu trả lời ở trên gợi ý sử dụng trong Global.asax.cs. Vì vậy, tôi đã phải làm rõ ràng như sau:

System.Web.HttpContext.Current.Session["blah"]

điều này đã giúp tôi, không chắc tôi có làm gì không ở đây không, nhưng tôi hy vọng nó sẽ giúp được ai đó!


6
System.Web.HttpContext.C hiện.Session ["blah"] = value
Tomasz Iniewicz

21

Vì tôi không thích nhìn thấy "HTTPContext.Cản.Session" về địa điểm, tôi sử dụng mẫu đơn để truy cập các biến phiên, nó giúp bạn dễ dàng truy cập vào túi dữ liệu được gõ mạnh.

[Serializable]
public sealed class SessionSingleton
{
    #region Singleton

    private const string SESSION_SINGLETON_NAME = "Singleton_502E69E5-668B-E011-951F-00155DF26207";

    private SessionSingleton()
    {

    }

    public static SessionSingleton Current
    {
        get
        {
            if ( HttpContext.Current.Session[SESSION_SINGLETON_NAME] == null )
            {
                HttpContext.Current.Session[SESSION_SINGLETON_NAME] = new SessionSingleton();
            }

            return HttpContext.Current.Session[SESSION_SINGLETON_NAME] as SessionSingleton;
        }
    }

    #endregion

    public string SessionVariable { get; set; }
    public string SessionVariable2 { get; set; }

    // ...

sau đó bạn có thể truy cập dữ liệu của mình từ bất cứ đâu:

SessionSingleton.Current.SessionVariable = "Hello, World!";

2
Vì vậy, lớp này có hai trách nhiệm: duy trì một thể hiện duy nhất và lưu trữ các biến ... Tôi sẽ sử dụng một thùng chứa IOC để có một singleton.
Jowen

1
Tuy nhiên, nếu bạn đã có một thiết lập, tôi cũng có thể tạo ra một dịch vụ phiên có thể tiêm đầy đủ, tuy nhiên, tính nhất quán có lẽ là lợi thế lớn nhất, tôi sẽ có xu hướng sử dụng mã này cho các ứng dụng web tính năng nhỏ .. webwizards nếu bạn muốn.
Chết. Sống

14

Nếu bạn đang sử dụng asp.net mvc, đây là một cách đơn giản để truy cập phiên.

Từ một bộ điều khiển:

{Controller}.ControllerContext.HttpContext.Session["{name}"]

Từ góc nhìn:

<%=Session["{name}"] %>

Đây chắc chắn không phải là cách tốt nhất để truy cập các biến phiên của bạn, nhưng nó là một tuyến trực tiếp. Vì vậy, hãy cẩn thận khi sử dụng (tốt nhất là trong quá trình tạo mẫu nhanh) và sử dụng Wrapper / Container và OnSessionStart khi nó trở nên phù hợp.

HTH


2
hm .. đó là cách tốt nhất? Tôi có nên truyền dữ liệu cho ViewState từ Phiên trên bộ điều khiển không?
RredCat

2
và bạn có thể giải thích sự co thắt của phương pháp này?
RredCat

1
Tôi nghĩ rằng anh ấy có nghĩa là tốt nhất nên có phương pháp đọc / ghi. Tùy thuộc vào việc sử dụng đồng thời / luồng, bạn cũng có thể cần khóa trong các phương thức đọc / ghi đó để tránh tình trạng đua.
DeepSpace101

13

Chà, IMHO ..

  1. không bao giờ tham khảo Phiên trong trang xem / trang chính của bạn
  2. giảm thiểu việc sử dụng phiên của bạn. MVC cung cấp TempData obj cho việc này, về cơ bản là Phiên hoạt động cho một chuyến đi đến máy chủ.

Liên quan đến # 1, tôi có Chế độ xem chính được gõ mạnh, có thuộc tính để truy cập bất cứ thứ gì mà đối tượng Phiên đại diện .... trong trường hợp của tôi, Chế độ xem chính được gõ mạnh mẽ giúp tôi linh hoạt với các trang Xem được gõ mạnh

ViewMasterPage<AdminViewModel>

AdminViewModel
{
    SomeImportantObjectThatWasInSession ImportantObject
}

AdminViewModel<TModel> : AdminViewModel where TModel : class
{
   TModel Content
}

và sau đó...

ViewPage<AdminViewModel<U>>

7

Mặc dù tôi không biết về asp.net mvc, nhưng đây là những gì chúng ta nên làm trong một trang web .net bình thường. Nó cũng nên làm việc cho asp.net mvc.

YourSessionClass obj=Session["key"] as YourSessionClass;
if(obj==null){
obj=new YourSessionClass();
Session["key"]=obj;
}

Bạn sẽ đặt cái này bên trong một phương thức để dễ dàng truy cập. HTH



7

Cách truy cập phiên của tôi là viết một lớp trình trợ giúp đóng gói các tên trường khác nhau và các loại của chúng. Tôi hy vọng ví dụ này giúp:

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.SessionState;

namespace dmkp
{
    /// <summary>
    /// Encapsulates the session state
    /// </summary>
    public sealed class LoginInfo
    {
        private HttpSessionState _session;
        public LoginInfo(HttpSessionState session)
        {
            this._session = session;
        }

        public string Username
        {
            get { return (this._session["Username"] ?? string.Empty).ToString(); }
            set { this._session["Username"] = value; }
        }

        public string FullName
        {
            get { return (this._session["FullName"] ?? string.Empty).ToString(); }
            set { this._session["FullName"] = value; }
        }
        public int ID
        {
            get { return Convert.ToInt32((this._session["UID"] ?? -1)); }
            set { this._session["UID"] = value; }
        }

        public UserAccess AccessLevel
        {
            get { return (UserAccess)(this._session["AccessLevel"]); }
            set { this._session["AccessLevel"] = value; }
        }

    }
}

Tôi thích câu trả lời của bạn ... bạn có thể giải thích thêm về những gì đang diễn ra ... và tại sao đây là một cách tiếp cận tốt hơn trái ngược với các câu trả lời khác trong chủ đề này.
Chef_Code

6

Những câu trả lời tuyệt vời từ các bạn nhưng tôi sẽ cảnh báo bạn không nên luôn dựa vào Phiên. Nó là nhanh chóng và dễ dàng để làm như vậy, và tất nhiên sẽ làm việc nhưng sẽ không tuyệt vời trong tất cả các cicrumstances.

Ví dụ: nếu bạn gặp phải tình huống trong đó lưu trữ của bạn không cho phép sử dụng phiên hoặc nếu bạn đang ở trong trang trại web hoặc trong ví dụ về ứng dụng SharePoint được chia sẻ.

Nếu bạn muốn một giải pháp khác, bạn có thể xem xét bằng cách sử dụng IOC Container, chẳng hạn như Castle Windsor , tạo một lớp nhà cung cấp làm trình bao bọc và sau đó giữ một phiên bản của lớp của bạn bằng cách sử dụng theo yêu cầu hoặc lối sống phiên tùy theo yêu cầu của bạn.

IOC sẽ đảm bảo rằng cùng một thể hiện được trả về mỗi lần.

Có phức tạp hơn, nếu bạn cần một giải pháp đơn giản chỉ cần sử dụng phiên.

Dưới đây là một số ví dụ thực hiện dưới đây quan tâm.

Sử dụng phương pháp này, bạn có thể tạo một lớp nhà cung cấp dọc theo dòng:

public class CustomClassProvider : ICustomClassProvider
{
    public CustomClassProvider(CustomClass customClass)
    { 
        CustomClass = customClass;
    }

    public string CustomClass { get; private set; }
}

Và đăng ký một cái gì đó như:

public void Install(IWindsorContainer container, IConfigurationStore store)
{
    container.Register(
            Component.For<ICustomClassProvider>().UsingFactoryMethod(
                () => new CustomClassProvider(new CustomClass())).LifestylePerWebRequest());
    }

4

Bạn có thể sử dụng ViewModelBase làm lớp cơ sở cho tất cả các mô hình, lớp này sẽ đảm nhiệm việc kéo dữ liệu từ phiên

class ViewModelBase 
{
  public User CurrentUser 
  {
     get { return System.Web.HttpContext.Current.Session["user"] as User };
     set 
     {
        System.Web.HttpContext.Current.Session["user"]=value; 
     }
  }
}

Bạn có thể viết một phương thức mở rộng trên HttpContextBase để xử lý dữ liệu phiên

T FromSession<T>(this HttpContextBase context ,string key,Action<T> getFromSource=null) 
{
    if(context.Session[key]!=null) 
    {
        return (T) context.Session[key];
    }
  else if(getFromSource!=null) 
  {
    var value = getFromSource();
   context.Session[key]=value; 
   return value; 
   }
  else 
  return null;
}

Sử dụng như dưới đây trong bộ điều khiển

User userData = HttpContext.FromSession<User>("userdata",()=> { return user object from service/db  }); 

Đối số thứ hai là tùy chọn, nó sẽ được sử dụng điền dữ liệu phiên cho khóa đó khi giá trị không có trong phiên.

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.