ASP.Net Session - PullRequest
       39

ASP.Net Session

24 голосов
/ 25 сентября 2008

Я хочу сохранить «состояние» некоторых действий, которые пользователь выполняет в серии различных веб-форм ASP.Net. Каков мой выбор для сохранения состояния и каковы плюсы / минусы каждого решения?

Я использую объекты Session и некоторые вспомогательные методы для строгой типизации объектов:

    public static Account GetCurrentAccount(HttpSessionState session)
    {
        return (Account)session[ACCOUNT];
    }

    public static void SetCurrentAccount(Account obj, HttpSessionState session)
    {
        session[ACCOUNT] = obj;
    }

В многочисленных источниках мне сказали, что "Сессия - это зло", так что это действительно коренная причина этого вопроса. Я хочу знать, что вы считаете «наилучшей практикой» и почему.

Ответы [ 13 ]

38 голосов
/ 25 сентября 2008

Нет ничего плохого в состоянии сеанса.

Есть несколько вещей, которые следует иметь в виду, которые могут вас укусить:

  1. Если пользователь нажимает кнопку возврата браузера, вы возвращаетесь на предыдущую страницу, но состояние вашего сеанса не возвращается. Таким образом, ваш CurrentAccount может отличаться от того, который был на странице.
  2. Процессы ASP.NET могут быть переработаны IIS. Когда это произойдет, ваш следующий запрос начнет новый процесс. Если вы используете в состоянии сеанса процесса значение по умолчанию, оно исчезнет: - (
  3. Сеанс также может быть прерван с тем же результатом, если пользователь некоторое время не активен. По умолчанию это 20 минут, поэтому хороший обед сделает это.
  4. Использование состояния сеанса вне процесса требует, чтобы все объекты, хранящиеся в состоянии сеанса, были сериализуемыми.
  5. Если пользователь откроет второе окно браузера, у него будет ожидаться второе и отличное приложение, но состояние сеанса, скорее всего, будет разделено между двумя. Таким образом, изменение CurrentAccount в одном окне браузера сделает то же самое в другом окне.
19 голосов
/ 25 сентября 2008

Два варианта временного хранения данных формы - это, во-первых, сохранение информации о каждой форме в переменных переменной состояния сеанса и, во-вторых, передача информации о форме с использованием параметров URL-адреса. Использование файлов cookie в качестве потенциального третьего варианта просто не работает по той простой причине, что у многих ваших посетителей, вероятно, отключены файлы cookie (однако это не влияет на файлы cookie сеанса). Кроме того, я предполагаю по характеру вашего вопроса, что вы не хотите хранить эту информацию в таблице базы данных, пока она не будет полностью зафиксирована.

Использование переменных Session является классическим решением этой проблемы, но оно имеет ряд недостатков. Среди них (1) большие объемы данных могут занимать ОЗУ сервера, если вы используете управление сеансами inproc, (2) совместное использование переменных сеанса между несколькими серверами в ферме серверов требует дополнительных соображений, и (3) профессионально разработанное приложение должно Защита от истечения сеанса (не просто приведите переменную сеанса, а используйте ее - если сеанс истек, приведение вызовет ошибку). Однако для подавляющего большинства приложений переменные сеанса, несомненно, являются подходящим способом.

Альтернативой является передача информации о каждой форме в URL. Основная проблема с этим подходом состоит в том, что вам нужно быть чрезвычайно осторожным в «передаче» информации. Например, если вы собираете информацию на четырех страницах, вам необходимо собрать информацию на первой странице, передать ее в URL-адресе на вторую страницу, где вы должны сохранить ее в состоянии просмотра этой страницы. Затем при вызове третьей страницы вы будете собирать данные формы со второй страницы, а также переменные состояния представления и кодировать их как в URL-адресе и т. Д. Если у вас есть пять или более страниц или если посетитель будет переходить по сайту, вы в ваших руках будет настоящий беспорядок. Имейте также в виду, что вся информация должна быть A) сериализована в строку, безопасную для URL, и B) закодирована таким образом, чтобы предотвратить простые взломы на основе URL (например, если вы указали цену открытым текстом и передали ее вместе кто-то может изменить цену). Обратите внимание, что вы можете уменьшить некоторые из этих проблем, создав своего рода «диспетчер сеансов» и заставив его управлять строками URL для вас, но вам все равно придется быть чрезвычайно чувствительным к возможности того, что любая данная ссылка может уничтожить весь сеанс, если он не управляется должным образом.

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

Итак, давайте предположим, что вы действительно управляете данными пользователя, используя встроенную возможность сеансов. Почему кто-то сказал бы вам, что "Сессия зла"? Ну, в дополнение к приведенным выше соображениям о загрузке памяти, ферме серверов и истечении срока действия, основной критике переменных Session является то, что они фактически являются нетипизированными переменными.

К счастью, осмотрительное использование переменных Session может избежать проблем с памятью (в любом случае большие базы данных должны храниться в базе данных), и если вы работаете с сайтом, достаточно большим, чтобы требовать ферму серверов, существует множество механизмов, доступных для создания общего состояния в ASP.NET (подсказка: вы не будете использовать inproc storage).

Чтобы избежать практически всех остальных недостатков Session, я рекомендую реализовать объект для хранения данных сеанса, а также некоторые простые возможности управления объектами Session. Затем встроите их в потомок класса Page и используйте этот класс Page для всех своих страниц. Тогда вам будет просто получить доступ к вашим данным Session через класс страницы в виде набора строго типизированных значений. Обратите внимание, что поля вашего объекта позволят вам получить доступ к каждой из ваших «переменных сеанса» строго типизированным способом (например, одно поле на переменную).

Дайте мне знать, если это простая задача для вас или вам нужен пример кода!

10 голосов
/ 25 сентября 2008

Насколько я знаю, Session является предполагаемым способом хранения этой информации. Пожалуйста, имейте в виду, что состояние сеанса обычно сохраняется в процессе по умолчанию. Если у вас несколько веб-серверов или происходит перезагрузка IIS, вы теряете состояние сеанса. Это можно исправить с помощью службы состояний ASP.NET или даже базы данных SQL для хранения сеансов. Это гарантирует, что люди вернут свой сеанс, даже если они перенаправлены на другой веб-сервер или в случае перезагрузки рабочего процесса.

6 голосов
/ 25 сентября 2008

Одна из причин его зловещей репутации заключается в том, что разработчики поспешили использовать его со строковыми литералами в коде пользовательского интерфейса (а не с помощью вспомогательного класса, подобного вашему) в качестве ключей элементов и в результате получили большую сумку непроверяемого беспорядочного состояния. Какой-то тип обертки является требованием начального уровня для использования не злой сессии.

6 голосов
/ 25 сентября 2008

Что касается "Злого бытия" ... если бы вы разрабатывали в классическом ASP, я бы согласился, но ASP.NET/IIS работает намного лучше.

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

Другие маленькие лакомые кусочки информации, которая не нуждается в долговременном постоянстве, мы используем комбинацию файлов cookie и viewstate.

5 голосов
/ 25 сентября 2008

Если вы хотите хранить информацию, к которой можно получить глобальный доступ, в вашем веб-приложении, вы можете использовать атрибут ThreadStatic. Это превращает static член Class в члена, который используется текущим потоком, но не другими потоками. Преимущество ThreadStatic в том, что вам не нужно иметь доступный веб-контекст. Например, если у вас есть серверная часть, которая не ссылается на System.Web, но также хочет поделиться информацией там, вы можете установить id пользователя в начале каждого запроса в свойстве ThreadStatic и ссылаться на него в вашей зависимости без необходимости иметь доступ к Session объекту.

Поскольку это static, но только для одного потока, мы гарантируем, что другие одновременные посетители не получат наш сеанс. Это работает, если вы гарантируете, что свойство сбрасывается для каждого запроса. Это делает его идеальным компаньоном для печенья.

3 голосов
/ 25 сентября 2008

Я думаю, что использование объекта Session в этом случае нормально, но вы должны помнить, что срок действия Session может истечь, если в течение длительного времени нет активности браузера ( Свойство HttpSessionState.Timeout определяет, сколько минут провайдер состояния сеанса завершает сеанс), поэтому перед возвратом лучше проверить наличие значения:

public static Account GetCurrentAccount(HttpSessionState session)
{
    if (Session[ACCOUNT]!=null)
        return (Account)Session[ACCOUNT];
    else
        throw new Exception("Can't get current account. Session expired.");
}
2 голосов
/ 25 сентября 2008
1 голос
/ 30 сентября 2008

Все, что вы помещаете в объект сеанса, остается там на время сеанса, пока оно не будет очищено. Плохое управление памятью, хранящейся с использованием inproc и stateserver, заставит вас масштабироваться раньше, чем необходимо. Сохраняйте только идентификатор сеанса / пользователя в сеансе и загружайте то, что необходимо, в объект кэша по требованию с помощью вспомогательного класса. Таким образом, вы можете точно настроить его время жизни в соответствии с тем, как часто эти данные мы использовали. Следующая версия asp.net может иметь распределенный кеш (слух).

1 голос
/ 25 сентября 2008

Я думаю, что "зло" происходит из-за чрезмерного использования сеанса. Если вы просто вставляете что-нибудь и все в это (например, используете глобальные переменные для всего), у вас будет плохая производительность и просто беспорядок.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...