Variabel sesi dalam ASP.NET MVC

169

Saya menulis aplikasi web yang akan memungkinkan pengguna untuk menjelajah ke beberapa halaman web dalam situs web yang membuat permintaan tertentu. Semua informasi yang input pengguna akan disimpan dalam objek yang saya buat. Masalahnya adalah bahwa saya memerlukan objek ini untuk diakses dari bagian mana pun dari situs web dan saya tidak benar-benar tahu cara terbaik untuk mencapai ini. Saya tahu bahwa salah satu solusinya adalah menggunakan variabel sesi tetapi saya tidak tahu bagaimana menggunakannya di asp .net MVC. Dan di mana saya akan mendeklarasikan variabel sesi? Apakah ada cara lain?

Draco
sumber
3
Anda mencampur konsep Situs Web dan Aplikasi Web ... mereka bukan hal yang sama.
adripanico
1
Kedengarannya seperti kebutuhan untuk database
Coops
1
Kemungkinan duplikat dari Bagaimana cara menggunakan sesi dalam aplikasi ASP.NET MVC 4?
Michael Freidgeim

Jawaban:

123

Saya akan berpikir Anda akan ingin memikirkan apakah semuanya benar-benar termasuk dalam keadaan sesi. Ini adalah sesuatu yang saya lakukan setiap sekarang dan kemudian dan ini adalah pendekatan yang sangat bagus untuk semuanya, tetapi Anda harus berhati-hati ketika meletakkan sesuatu dalam konteks sesi. Tidak semuanya harus ada di sana hanya karena itu milik beberapa pengguna.

di global.asax mengaitkan acara OnSessionStart

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

Dari mana saja dalam kode di mana properti HttpContext.Current! = Null Anda dapat retrive objek itu. Saya melakukan ini dengan metode ekstensi.

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

Dengan cara ini Anda bisa dalam kode

void OnLoad(...)
{
    var sessionObj = HttpContext.Current.GetMySessionObject();
    // do something with 'sessionObj'
}
John Leidegren
sumber
32
Jika ASP MVC sedang digunakan maka lebih disukai untuk tidak menggunakan objek Sesi yang sebenarnya dari HttpContext.Current.Session tetapi untuk menggunakan HttpSessionStateWrapper & HttpSessionStateBase baru dari System.Web.Abstractions.dll kemudian gunakan Pabrik atau DI untuk mendapatkan Sesi.
Paul
6
Bagaimana Anda menetapkan sesuatu ke variabel sesi? (Berbeda dengan hanya mengakses)
raklos
31
Untuk orang yang mencari tahu apa acara "OnSessionStart" dan bagaimana Anda "mengaitkannya", lihat stackoverflow.com/questions/1531125/…
Cephron
5
@ Paul Apakah Anda bisa memberikan contoh? Saya tidak dapat menemukan contoh menggunakan HttpSessionStateWrapper.
Joseph Woodward
4
@AjayKelkar Utas komentar ini menyarankan "Jika ASP MVC sedang digunakan maka lebih disukai untuk tidak menggunakan objek Sesi yang sebenarnya dari HttpContext.Current.Session tetapi menggunakan HttpSessionStateWrapper & HttpSessionStateBase" baru yang menyarankan jawaban Anda tidak lebih baik
Coops
48

Jawabannya di sini benar, namun saya berjuang untuk mengimplementasikannya dalam aplikasi ASP.NET MVC 3. Saya ingin mengakses objek Sesi di controller dan tidak tahu mengapa saya terus mendapatkan "Instance tidak diatur ke instance dari kesalahan Object". Apa yang saya perhatikan adalah bahwa dalam pengontrol ketika saya mencoba mengakses sesi dengan melakukan hal berikut, saya terus mendapatkan kesalahan itu. Ini disebabkan oleh fakta bahwa this.HttpContext adalah bagian dari objek Controller.

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

Namun, apa yang saya inginkan adalah HttpContext yang merupakan bagian dari namespace System.Web karena ini adalah jawaban yang disarankan untuk digunakan di Global.asax.cs di atas. Jadi saya harus secara eksplisit melakukan hal berikut:

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

ini membantu saya, tidak yakin apakah saya melakukan sesuatu yang bukan MO di sekitar sini, tapi saya harap ini membantu seseorang!

Tomasz Iniewicz
sumber
6
System.Web.HttpContext.Current.Session ["blah"] = value
Tomasz Iniewicz
21

Karena saya tidak suka melihat "HTTPContext.Current.Session" tentang tempat itu, saya menggunakan pola tunggal untuk mengakses variabel sesi, ini memberi Anda akses yang mudah untuk mengetik data yang sangat diketik.

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

    // ...

maka Anda dapat mengakses data Anda dari mana saja:

SessionSingleton.Current.SessionVariable = "Hello, World!";
Mati
sumber
2
Jadi kelas ini memiliki dua tanggung jawab: mempertahankan satu instance, dan menyimpan variabel ... Saya akan menggunakan wadah IOC untuk memiliki singleton.
Jowen
1
Jika Anda sudah memiliki satu pengaturan, saya mungkin akan membuat layanan sesi injeksi lengkap juga, meskipun, konsistensi mungkin keuntungan terbesar, saya akan lebih cenderung menggunakan kode ini untuk webapps featureset kecil .. webwizards jika Anda mau.
Mati. Sabit
14

Jika Anda menggunakan asp.net mvc, berikut adalah cara sederhana untuk mengakses sesi.

Dari Pengendali:

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

Dari Tampilan:

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

Ini jelas bukan cara terbaik untuk mengakses variabel sesi Anda, tetapi ini adalah rute langsung. Jadi gunakan dengan hati-hati (lebih disukai selama prototyping cepat), dan gunakan Wrapper / Container dan OnSessionStart ketika itu menjadi tepat.

HTH

robertz
sumber
2
hm .. Jalan mana yang terbaik? Saya harus meneruskan data ke ViewState dari Session pada controller, bukan?
RredCat
2
dan bisakah Anda menjelaskan batasan metode ini?
RredCat
1
Saya pikir maksudnya lebih baik memiliki metode baca / tulis. Bergantung pada penggunaan konkurensi / utas, Anda mungkin juga perlu kunci dalam metode baca / tulis untuk menghindari kondisi balapan.
DeepSpace101
13

Baiklah, IMHO ..

  1. jangan pernah mereferensikan Sesi di dalam halaman tampilan / master Anda
  2. meminimalkan penggunaan Sesi Anda. MVC menyediakan TempData obj untuk ini, yang pada dasarnya adalah Sesi yang hidup untuk satu perjalanan ke server.

Berkenaan dengan # 1, saya memiliki Tampilan Master sangat diketik yang memiliki properti untuk mengakses apa pun yang mewakili objek Sesi .... dalam contoh saya Master View diketik adalah generik yang memberi saya beberapa fleksibilitas sehubungan dengan Lihat Halaman diketik kuat

ViewMasterPage<AdminViewModel>

AdminViewModel
{
    SomeImportantObjectThatWasInSession ImportantObject
}

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

lalu...

ViewPage<AdminViewModel<U>>
E Rolnicki
sumber
7

Meskipun saya tidak tahu tentang asp.net mvc, tetapi ini adalah apa yang harus kita lakukan di situs web .net biasa. Ini harus bekerja untuk asp.net mvc juga.

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

Anda akan meletakkan ini di dalam metode untuk akses mudah. HTH

DotNET
sumber
7

Cara saya mengakses sesi adalah menulis kelas pembantu yang merangkum berbagai nama bidang dan tipenya. Saya harap contoh ini membantu:

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

    }
}
Daniel
sumber
Saya suka jawaban Anda ... dapatkah Anda menguraikan lebih lanjut apa yang sedang terjadi ... dan mengapa ini merupakan pendekatan yang lebih baik berlawanan dengan jawaban lain di utas ini.
Chef_Code
6

Jawaban yang bagus dari teman-teman tetapi saya akan memperingatkan Anda agar tidak selalu mengandalkan Sesi. Ini cepat dan mudah untuk melakukannya, dan tentu saja akan berhasil tetapi tidak akan bagus dalam semua keadaan.

Misalnya jika Anda mengalami skenario di mana hosting Anda tidak mengizinkan penggunaan sesi, atau jika Anda berada di web farm, atau dalam contoh aplikasi SharePoint yang dibagikan.

Jika Anda menginginkan solusi yang berbeda, Anda bisa melihat menggunakan Kontainer IOC seperti Castle Windsor , membuat kelas penyedia sebagai pembungkus dan kemudian menjaga satu contoh kelas Anda menggunakan per permintaan atau gaya hidup sesi tergantung pada kebutuhan Anda.

IOC akan memastikan bahwa instance yang sama dikembalikan setiap kali.

Lebih rumit ya, jika Anda membutuhkan solusi sederhana cukup gunakan sesi.

Berikut adalah beberapa contoh implementasi di bawah ini yang tidak menarik.

Dengan menggunakan metode ini Anda bisa membuat kelas penyedia di sepanjang baris:

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

    public string CustomClass { get; private set; }
}

Dan daftarkan sesuatu seperti:

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

Anda dapat menggunakan ViewModelBase sebagai kelas dasar untuk semua model, kelas ini akan menangani penarikan data dari sesi

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

Anda dapat menulis metode ekstensi pada HttpContextBase untuk menangani data sesi

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

Gunakan ini seperti di bawah ini di controller

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

Argumen kedua adalah opsional itu akan digunakan mengisi data sesi untuk kunci itu ketika nilai tidak ada dalam sesi.

Ajay Kelkar
sumber