Где лучше всего хранить пользовательский объект User на время сеанса ASP.NET?

У меня есть приложение ASP.NET, которому необходимо запомнить некоторую информацию о пользователе (и из какой он компании) на разных страницах в рамках сеанса.

Я предполагаю, что это требование практически любого приложения ASP.NET определенного размера. Я использовал несколько разных подходов на протяжении многих лет.

В прошлом я передал идентификатор в параметрах строки запроса следующим образом:

site.com/page.aspx?usrid=1&companyid=2

а затем создал экземпляр объекта на каждой странице (из базы данных).

Другой распространенный способ сделать это — сохранить мои объекты в переменных сеанса:

Session["User"] = currentUser;              // store at login
User currentUser = (User)Session["User"];   // retrieve on some other page

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

Недавно я унаследовал приложение, которое использует общедоступные свойства на главной странице, например:

Master.theUser = currentUser;         // store at login
User currentUser = Master.theUser;    // retrieve on some other page

Это сохраняет актерский состав и, как мне кажется, выглядит более читабельно, но я не знаю, лучше это или хуже с точки зрения производительности. У него также есть некоторая логика в геттере, где, если частное значение равно нулю, он пытается получить его из переменной Session, хотя я не уверен, что это никогда не использовалось (или использовалось каждый get!? ) или что.

Моя последняя идея - использовать мой класс страницы. У меня есть пользовательский класс страницы, производный от стандартного базового класса System.Web.UI.Page. Он включает такие объекты, как CurrentUser, в качестве общедоступных свойств. Кажется, это работает нормально. Мне это даже больше нравится.

Но я действительно не знаю, что происходит под одеялом. Может ли кто-нибудь дать мнение о том, какой подход лучше и почему?

Альтернативные предложения для этого также приветствуются.

Обновление: я проверил использование trace.axd и Trace.Write, и оказалось, что ни версия мастер-страницы, ни версия пользовательского класса страницы не «запоминают» значения между страницами. В методах "get" есть строка кода, которая проверяет, является ли свойство User пустым, и если да, то считывает его из переменной сеанса. Это происходит, когда страница обращается к свойству (Master.User или производному классу this.User) в первый раз на данной странице, тогда последующие запросы могут получить значение (без обращения к переменной сеанса).


person MGOwen    schedule 06.07.2010    source источник
comment
К вашему сведению, производительность должна быть на последнем месте в вашем списке проблем. Вытягивание объекта из сеанса имеет чрезвычайно низкие накладные расходы. Простота использования и инкапсуляция важны, оптимизация — нет.   -  person Rex M    schedule 07.07.2010


Ответы (3)


Сессия была разработана именно для этой цели. Он хранит соответствующие данные на протяжении всего «сеанса» пользователя, который, я думаю, составляет 20 минут, или пользователь закрывает браузер. Если вас беспокоит размер вашего объекта User, вы можете просто сохранить идентификатор, а затем получить объект из БД, но вы должны взвесить компромисс между двусторонним обходом БД. Однако я не думаю, что это обычно касается сеанса, потому что он не отправляется клиенту, как ViewState. Вы также можете предоставить это значение сеанса с помощью свойства, как в примере Curious Geek, но использовать объект Session вместо объекта ViewState.

Установка свойства на главной странице не будет работать, потому что это только член созданного в данный момент класса, который собирает мусор в конце каждого запроса, поэтому у вас не будет его в следующем запросе.

Вот краткий обзор управления состоянием в ASP.NET: http://msdn.microsoft.com/en-us/library/75x4ha6s.aspx

person Dave Thieben    schedule 06.07.2010

Я согласен с вашей latest идеей. Пусть базовый класс общей страницы предоставляет общедоступное свойство типа user. Свойство должно читать/записывать из/в сеансовый ключ. У нас также есть другое свойство под названием GoBackPage, которое сохраняет URL-адрес предыдущей страницы в состоянии просмотра текущей страницы.

    public string GoBackPage
    {
        get
        {
            return this.ViewState["__PrevPage"].ToString();
        }

        set
        {
            this.ViewState["__PrevPage"] = value;
        }
    }

Вы все еще можете пойти дальше и сохранить только UserId в состоянии просмотра и предоставить свойство в общем базовом классе страницы, которое будет считывать UserId из состояния просмотра и возвращать пользовательский объект.

person this. __curious_geek    schedule 06.07.2010
comment
Хранение UserId в ViewState не сохранит его на разных страницах. Он будет доступен только в обратных передачах на этой одной странице (даже если она находится в базовом классе). - person Dave Thieben; 06.07.2010
comment
Я бы не стал хранить информацию о пользователе в состоянии просмотра: 1) Использование ViewState увеличивает объем данных, которые должны быть возвращены вашему клиенту. 2) поскольку состояние просмотра является клиентским и небезопасным, вы можете зашифровать состояние просмотра, но это также будет огромным ударом по производительности. Использование сеанса - это путь! - person Anthony; 06.07.2010

Пока лучшее решение выглядит примерно так:

public class MyPage : System.Web.UI.Page
{


private User user;
public User User
{
    get
    {                   
        if (user == null)
        {
        user = (User)HttpContext.Current.Session["CurrentUser"];    //check if session[CurrentUser] is null here and log them out if so?
        }
        return user;
    }
    set
    {
        user = value;
        HttpContext.Current.Session["CurrentUser"] = value;
    }
}

}

Затем на любой странице webpage.aspx.cs вы можете сделать что-то вроде этого:

UsernameTextBox.Text = User.FullName;

Он попадет в сеанс при первом использовании, но последующее использование на конкретной странице будет быстрее.

Код в различных классах и выделенном коде теперь выглядит намного аккуратнее, потому что мне не нужно читать и приводить свой объект User (и объект Company и т. д.) из Session каждый раз, когда я его использую.

person MGOwen    schedule 23.02.2012