Переменные сеанса в ASP.NET MVC - PullRequest
       48

Переменные сеанса в ASP.NET MVC

165 голосов
/ 18 февраля 2009

Я пишу веб-приложение, которое позволит пользователю просматривать несколько веб-страниц на сайте, делая определенные запросы. Вся информация, которую вводит пользователь, будет храниться в объекте, который я создал. Проблема в том, что мне нужен доступ к этому объекту из любой части сайта, и я не знаю, как лучше всего это сделать. Я знаю, что одним из решений является использование переменных сеанса, но я не знаю, как их использовать в asp .net MVC. И где бы я объявил переменную сеанса? Есть ли другой способ?

Ответы [ 10 ]

123 голосов
/ 18 февраля 2009

Я думаю, вы захотите подумать, действительно ли вещи принадлежат состоянию сеанса. Это то, что я делаю время от времени, и это хороший строго типизированный подход ко всему, но вы должны быть осторожны, когда помещаете вещи в контекст сессии. Не все должно быть там только потому, что оно принадлежит какому-то пользователю.

в 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'
}
44 голосов
/ 24 сентября 2011

Ответ здесь правильный, однако я изо всех сил пытался реализовать его в приложении ASP.NET MVC 3. Я хотел получить доступ к объекту Session в контроллере и не мог понять, почему я продолжал получать «Экземпляр не установлен в экземпляр ошибки объекта». Я заметил, что в контроллере, когда я пытался получить доступ к сеансу, выполняя следующее, я продолжал получать эту ошибку. Это связано с тем, что this.HttpContext является частью объекта Controller.

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

Однако я хотел, чтобы был HttpContext, который является частью пространства имен System.Web, потому что именно этот ответ, предложенный выше, предлагает использовать в Global.asax.cs. Поэтому мне пришлось явно сделать следующее:

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

это помогло мне, не уверен, что я сделал что-то, кроме М.О. где-то здесь, но я надеюсь, что это кому-то поможет!

20 голосов
/ 10 мая 2012

Поскольку мне не нравится видеть «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!";
14 голосов
/ 23 апреля 2009

Если вы используете asp.net mvc, вот простой способ получить доступ к сеансу.

с контроллера:

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

Из вида:

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

Это определенно не лучший способ доступа к переменным сеанса, но это прямой маршрут. Поэтому используйте его с осторожностью (желательно во время быстрого создания прототипа) и используйте Wrapper / Container и OnSessionStart, когда это станет уместным.

НТН

13 голосов
/ 18 февраля 2009

Ну, ИМХО ..

  1. никогда не ссылаться на сеанс внутри вашей страницы просмотра / главной страницы
  2. свести к минимуму использование сеанса. Для этого MVC предоставляет объект TempData, который, по сути, является сеансом, который работает в течение одной поездки на сервер.

Что касается # 1, у меня есть строго типизированный Master View, у которого есть свойство для доступа ко всему, что представляет объект Session .... в моем случае, строго типизированный Master View является универсальным, что дает мне некоторую гибкость в отношении сильно набрал View Pages

ViewMasterPage<AdminViewModel>

AdminViewModel
{
    SomeImportantObjectThatWasInSession ImportantObject
}

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

, а затем ...

ViewPage<AdminViewModel<U>>
7 голосов
/ 15 июня 2011

Есть 3 способа сделать это.

  1. Вы можете получить прямой доступ HttpContext.Current.Session

  2. Можно издеваться HttpContextBase

  3. Создание метода расширения для HttpContextBase

Я предпочитаю 3-й способ. Эта ссылка - хорошая ссылка.

Получить / установить методы сеанса HttpContext в BaseController против Mocking HttpContextBase для создания методов Get / Set

7 голосов
/ 18 февраля 2009

Хотя я не знаю насчет asp.net mvc, но это то, что мы должны делать на обычном .net сайте. Это должно работать и для asp.net mvc.

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

Вы бы поместили это в метод для легкого доступа. НТН

6 голосов
/ 24 февраля 2012

Отличные ответы от ребят, но я бы предостерег вас от того, чтобы всегда полагаться на сессию. Это быстро и легко сделать, и, конечно, будет работать, но не будет хорошо во всех случаях.

Например, если вы столкнулись со сценарием, в котором ваш хостинг не позволяет использовать сеанс, или если вы находитесь в веб-ферме, или в примере общего приложения SharePoint.

Если вам нужно другое решение, вы можете использовать Контейнер IOC , например 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 голосов
/ 18 мая 2016

Мой способ доступа к сеансам - написать вспомогательный класс, который инкапсулирует различные имена полей и их типы. Я надеюсь, что этот пример поможет:

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

    }
}
4 голосов
/ 06 июля 2014

Вы можете использовать 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  }); 

Второй аргумент является необязательным, он будет использоваться для заполнения данных сеанса для этого ключа, когда значение не присутствует в сеансе.

...