Змінні сесії в ASP.NET MVC


169

Я пишу веб-програму, яка дозволить користувачу переглядати кілька веб-сторінок на веб-сайті, роблячи певні запити. Вся інформація, яку вводить користувач, буде зберігатися в створеному мною об’єкті. Проблема полягає в тому, що мені потрібен доступ до цього об’єкта з будь-якої частини веб-сайту, і я не знаю найкращого способу цього досягти. Я знаю, що одним із варіантів є використання змінних сеансу, але я не знаю, як їх використовувати в asp .net MVC. І де я б оголосив змінну сеансу? Чи є інший спосіб?


3
Ви змішуєте веб-сайт та концепції веб-додатків ... вони не одне і те ж.
adripanico


Відповіді:


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. Я хотів отримати доступ до об'єкта Session в контролері і не зміг зрозуміти, чому я продовжував отримувати "Екземпляр не встановлений на екземпляр помилки Object". Що я помітив, це те, що в контролері, коли я намагався отримати доступ до сеансу, виконуючи наступні дії, я продовжував отримувати цю помилку. Це пов'язано з тим, що this.HttpContext є частиною об'єкта Controller.

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, щоб мати синглтон.
Джовен

1
Якщо у вас вже є одна установка, я, мабуть, також зробив повноцінну послугу сеансів для ін'єкцій, хоча консистенції, мабуть, є найбільшою перевагою, я б більше схильний використовувати цей код для невеликих наборів функцій webapps .. веб-майстрів, якщо ви хочете.
Dead.Rabit

14

Якщо ви використовуєте mpc asp.net, ось простий спосіб отримати доступ до сеансу.

Від контролера:

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

З виду:

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

Це, безумовно, не найкращий спосіб отримати доступ до змінних сеансів, але це прямий маршрут. Тому використовуйте його обережно (бажано під час швидкого складання прототипів) та використовуйте Wrapper / Container та OnSessionStart, коли це стане доречним.

HTH


2
хм .. Який найкращий спосіб? Я повинен передати дані ViewState з сесії на контролері, чи не так?
RredCat

2
і ви могли б пояснити обмеження цього методу?
RredCat

1
Я думаю, що він мав на увазі, що найкраще мати методи читання / запису. Залежно від використання одночасності / потоку, вам також можуть знадобитися блокування в цих методах читання / запису, щоб уникнути перегонів.
DeepSpace101

13

Ну, ІМХО ..

  1. ніколи не посилайтеся на сеанс всередині перегляду / головної сторінки
  2. мінімізуйте використання сесії. MVC надає TempData obj для цього, що в основному є Сесією, яка живе для однієї поїздки на сервер.

Що стосується №1, у мене є сильно набраний Master View, який має властивість отримувати доступ до того, що представляє об'єкт Session .... у моєму випадку надзвичайно типізований Master View є загальним, що дає мені певну гнучкість щодо сильно набраних сторінок перегляду

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 проти глузуючого HttpContextBase для створення методів Get / Set


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.

Якщо ви хочете іншого рішення, можете поглянути на використання контейнера МОК, такого як Castle Windsor , створити клас постачальника як обгортку, а потім зберегти один екземпляр свого класу, використовуючи спосіб запиту або спосіб сесії залежно від ваших вимог.

МОК забезпечить, щоб кожен і той же екземпляр повертався.

Складніше так, якщо вам потрібно просте рішення просто скористайтеся сеансом.

Ось декілька прикладів реалізації нижче, що не цікавлять.

За допомогою цього методу ви можете створити клас постачальника відповідно до:

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

Другий аргумент необов’язковий, він буде використаний для заповнення даних сеансу для цього ключа, коли значення немає в сеансі.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.