ตัวแปรเซสชันใน ASP.NET MVC


169

ฉันกำลังเขียนแอปพลิเคชันเว็บที่จะอนุญาตให้ผู้ใช้เรียกดูหน้าเว็บหลายหน้าภายในเว็บไซต์ที่มีการร้องขอบางอย่าง ข้อมูลทั้งหมดที่ผู้ใช้ป้อนจะถูกเก็บไว้ในวัตถุที่ฉันสร้างขึ้น ปัญหาคือฉันต้องการให้วัตถุนี้เข้าถึงได้จากส่วนใด ๆ ของเว็บไซต์และฉันไม่รู้วิธีที่ดีที่สุดในการทำสิ่งนี้ ฉันรู้ว่าทางออกหนึ่งคือการใช้ตัวแปรเซสชัน แต่ฉันไม่ทราบวิธีการใช้พวกเขาใน asp .net MVC และฉันจะประกาศตัวแปรเซสชันได้ที่ไหน? มีวิธีอื่น ๆ ?


3
คุณกำลังผสมแนวคิดเกี่ยวกับเว็บไซต์และแอปพลิเคชันเว็บ ... มันไม่เหมือนกัน
adripanico

1
ดูเหมือนต้องการฐานข้อมูล
Coops

คำตอบ:


123

ฉันจะคิดว่าคุณต้องการที่จะคิดว่าสิ่งที่อยู่ในสถานะเซสชัน นี่คือสิ่งที่ฉันพบว่าตัวเองกำลังทำอยู่ทุกขณะแล้วมันเป็นวิธีที่ดีที่จะพิมพ์สิ่งที่ดี แต่คุณควรระวังเมื่อวางสิ่งต่าง ๆ ในบริบทเซสชัน ไม่ใช่ทุกสิ่งควรอยู่ที่นั่นเพราะเป็นของผู้ใช้บางคน

ใน global.asax ขอเกี่ยวกับเหตุการณ์ OnSessionStart

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

จากที่ใดก็ได้ในรหัสที่คุณสมบัติ HttpContext.Current! = null คุณสามารถย้อนกลับวัตถุนั้นได้ ฉันทำสิ่งนี้ด้วยวิธีการขยาย

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

วิธีนี้คุณสามารถในรหัส

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

32
ถ้ามีการใช้ ASP MVC คุณไม่ควรใช้วัตถุเซสชันจริงจาก HttpContext.Current.Session แต่ใช้ HttpSessionStateWrapper & HttpSessionStateBase ใหม่จาก System.Web.Abstractions.dll จากนั้นใช้ Factory หรือ DI เพื่อรับเซสชัน
พอล

6
คุณจะกำหนดบางสิ่งให้กับตัวแปรเซสชันได้อย่างไร (ตรงข้ามกับที่เพิ่งเข้าถึง)
raklos

31
สำหรับผู้ที่พยายามคิดว่าเหตุการณ์ "OnSessionStart" คืออะไรและคุณ "ขอ" ได้อย่างไรดูที่stackoverflow.com/questions/1531125/ …
Cephron

5
@Paul คุณสามารถยกตัวอย่างได้หรือไม่? ฉันไม่พบตัวอย่างการใช้ HttpSessionStateWrapper
โจเซฟวู้ดเวิร์ด

4
@AjayKelkar กระทู้ความคิดเห็นนี้แนะนำ "ถ้า ASP MVC กำลังใช้งานอยู่จะดีกว่าถ้าไม่ใช้วัตถุเซสชันจริงจาก HttpContext.Current.Session แต่ใช้ HttpSessionStateWrapper & HttpSessionStateBase ใหม่" ซึ่งแนะนำคำตอบของคุณไม่ดีกว่า
Coops

48

คำตอบที่นี่ถูกต้อง แต่ฉันพยายามที่จะนำไปใช้ในแอป ASP.NET MVC 3 ฉันต้องการเข้าถึงเซสชันวัตถุในคอนโทรลเลอร์และไม่สามารถเข้าใจได้ว่าทำไมฉันถึงได้รับ "อินสแตนซ์ไม่ได้ตั้งค่าเป็นอินสแตนซ์ของข้อผิดพลาด Object" สิ่งที่ฉันสังเกตเห็นคือในตัวควบคุมเมื่อฉันพยายามเข้าถึงเซสชันโดยทำสิ่งต่อไปนี้ฉันยังคงได้รับข้อผิดพลาดนั้น นี่คือความจริงที่ว่านี้ HttpContext เป็นส่วนหนึ่งของวัตถุตัวควบคุม

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

อย่างไรก็ตามสิ่งที่ฉันต้องการคือ HttpContext ที่เป็นส่วนหนึ่งของ System.Web เนมสเปซเพราะนี่คือคำตอบที่แนะนำข้างต้นเพื่อใช้ใน Global.asax.cs ดังนั้นฉันต้องทำสิ่งต่อไปนี้อย่างชัดเจน:

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

สิ่งนี้ช่วยฉันไม่แน่ใจว่าฉันทำอะไรที่ไม่ได้อยู่ที่นี่ แต่ฉันหวังว่ามันจะช่วยใครซักคน!


6
System.Web.HttpContext.Current.Session ["blah"] = ค่า
Tomasz Iniewicz

21

เนื่องจากฉันไม่ชอบการดู "HTTPContext.Current.Session" เกี่ยวกับสถานที่นี้ฉันใช้รูปแบบซิงเกิลเพื่อเข้าถึงตัวแปรเซสชั่นมันช่วยให้คุณเข้าถึงข้อมูลที่พิมพ์อย่างรุนแรง

[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; }

    // ...

จากนั้นคุณสามารถเข้าถึงข้อมูลได้จากทุกที่:

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

2
ดังนั้นคลาสนี้มีความรับผิดชอบสองประการ: รักษาอินสแตนซ์เดียวและเก็บตัวแปร ... ฉันจะใช้คอนเทนเนอร์ IOC เพื่อมีซิงเกิล
Jowen

1
หากคุณมีการตั้งค่าหนึ่งแล้วฉันอาจจะให้บริการเซสชั่นการฉีดเต็มความสามารถเช่นกันแม้ว่าความสอดคล้องอาจเป็นข้อได้เปรียบที่ใหญ่ที่สุดฉันมีแนวโน้มที่จะใช้รหัสนี้สำหรับ webapps ชุดเล็ก ๆ .. webwizards ถ้าคุณต้องการ
Dead.Rabit

14

หากคุณใช้ asp.net mvc นี่เป็นวิธีที่ง่ายในการเข้าถึงเซสชัน

จากตัวควบคุม:

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

จากมุมมอง:

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

นี่ไม่ใช่วิธีที่ดีที่สุดในการเข้าถึงตัวแปรเซสชันของคุณ แต่เป็นเส้นทางโดยตรง ดังนั้นควรใช้ด้วยความระมัดระวัง (โดยเฉพาะในช่วงการสร้างต้นแบบอย่างรวดเร็ว) และใช้ Wrapper / Container และ OnSessionStart เมื่อเหมาะสม

HTH


2
หืมม. วิธีไหนดีที่สุด? ฉันควรส่งข้อมูลไปยัง ViewState จาก Session on controller ไม่ใช่เหรอ?
RredCat

2
และคุณสามารถอธิบายข้อ จำกัด ของวิธีนี้ได้หรือไม่?
RredCat

1
ฉันคิดว่าเขาหมายถึงว่าวิธีที่ดีที่สุดในการอ่าน / เขียน ขึ้นอยู่กับการใช้งานพร้อมกัน / เธรดคุณอาจต้องล็อกในวิธีการอ่าน / เขียนเพื่อหลีกเลี่ยงสภาวะการแข่งขัน
DeepSpace101

13

IMHO ..

  1. อย่าอ้างอิงเซสชันในหน้ามุมมอง / มาสเตอร์ของคุณ
  2. ลดการใช้งานเซสชันของคุณ MVC นำเสนอ TempData obj สำหรับสิ่งนี้ซึ่งโดยทั่วไปจะเป็นเซสชันที่มีชีวิตอยู่สำหรับการเดินทางไปยังเซิร์ฟเวอร์ครั้งเดียว

ในส่วนที่เกี่ยวกับ # 1 ฉันมีมุมมองมาสเตอร์ที่พิมพ์อย่างรุนแรงซึ่งมีคุณสมบัติในการเข้าถึงสิ่งที่วัตถุเซสชันแสดงให้เห็น .... ในกรณีของฉันมุมมองมาสเตอร์ที่พิมพ์อย่างหนักแน่นเป็นเรื่องทั่วไปซึ่งทำให้ฉันมีความยืดหยุ่น

ViewMasterPage<AdminViewModel>

AdminViewModel
{
    SomeImportantObjectThatWasInSession ImportantObject
}

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

แล้ว ...

ViewPage<AdminViewModel<U>>

7

แม้ว่าฉันไม่รู้เกี่ยวกับ asp.net mvc แต่นี่คือสิ่งที่เราควรทำในเว็บไซต์. net ปกติ มันควรจะทำงานกับ asp.net mvc ด้วย

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

คุณจะวางสิ่งนี้ไว้ในวิธีที่เข้าถึงได้ง่าย HTH


7

มี 3 วิธีในการทำ

  1. คุณสามารถเข้าถึงได้โดยตรง HttpContext.Current.Session

  2. คุณสามารถเยาะเย้ย HttpContextBase

  3. สร้างวิธีการขยายสำหรับ HttpContextBase

ฉันชอบวิธีที่ 3 ลิงค์นี้เป็นข้อมูลอ้างอิงที่ดี

รับ / ตั้งค่าวิธีการเซสชัน HttpContext ใน BaseController vs การเยาะเย้ย HttpContextBase เพื่อสร้างวิธีการรับ / ตั้งค่า


7

วิธีของฉันในการเข้าถึงเซสชันคือการเขียนคลาสตัวช่วยซึ่งห่อหุ้มชื่อฟิลด์และประเภทต่างๆ ฉันหวังว่าตัวอย่างนี้ช่วย:

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; }
        }

    }
}

ฉันชอบคำตอบของคุณ ... คุณช่วยอธิบายเพิ่มเติมว่าเกิดอะไรขึ้น ... และทำไมนี่จึงเป็นวิธีการที่ดีกว่าเมื่อเทียบกับคำตอบอื่น ๆ ในกระทู้นี้
Chef_Code

6

คำตอบที่ยอดเยี่ยมจากพวก แต่ฉันจะเตือนคุณจากการใช้เซสชั่นเสมอ มันง่ายและรวดเร็วในการทำเช่นนั้นและแน่นอนว่าจะใช้ได้ แต่จะไม่ดีในทุก ๆ

ตัวอย่างเช่นหากคุณพบสถานการณ์ที่โฮสติ้งของคุณไม่อนุญาตให้ใช้เซสชันหรือหากคุณอยู่ในเว็บฟาร์มหรือในตัวอย่างของแอปพลิเคชัน SharePoint ที่ใช้ร่วมกัน

หากคุณต้องการโซลูชันที่แตกต่างคุณสามารถดูการใช้IOC Containerเช่นCastle Windsorสร้างคลาสผู้ให้บริการเป็น wrapper แล้วเก็บอินสแตนซ์หนึ่งของคลาสของคุณโดยใช้การร้องขอหรือไลฟ์สไตล์เซสชันตามความต้องการของคุณ

IOC จะตรวจสอบให้แน่ใจว่าส่งคืนอินสแตนซ์เดียวกันทุกครั้ง

มีความซับซ้อนมากขึ้นใช่ถ้าคุณต้องการโซลูชันที่เรียบง่ายเพียงแค่ใช้เซสชั่น

นี่คือตัวอย่างการใช้งานด้านล่างที่คุณสนใจ

การใช้วิธีนี้คุณสามารถสร้างคลาสผู้ให้บริการตามบรรทัดต่อไปนี้:

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

    public string CustomClass { get; private set; }
}

และลงทะเบียนมันเหมือน:

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

4

คุณสามารถใช้ ViewModelBase เป็นคลาสพื้นฐานสำหรับทุกรุ่นคลาสนี้จะดูแลการดึงข้อมูลจากเซสชัน

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

คุณสามารถเขียนวิธีการขยายบน HttpContextBase เพื่อจัดการกับข้อมูลเซสชัน

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;
}

ใช้สิ่งนี้เหมือนด้านล่างในคอนโทรลเลอร์

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

อาร์กิวเมนต์ที่สองเป็นทางเลือกซึ่งจะใช้เติมข้อมูลเซสชันสำหรับคีย์นั้นเมื่อไม่มีค่าอยู่ในเซสชัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.