Вопрос

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

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

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

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

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

Это было полезно?

Решение

В состоянии сеанса нет ничего плохого по своей сути.

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

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

Другие советы

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

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

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

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

Предположим, что вы действительно будете управлять данными пользователя, используя встроенные возможности сеансов.Почему кто-то сказал вам, что «Сессия — это зло»?Что ж, в дополнение к соображениям о загрузке памяти, ферме серверов и сроку действия, представленным выше, основная критика переменных сеанса заключается в том, что они, по сути, являются нетипизированными переменными.

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

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

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

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

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

Что касается «Сессии быть злом»…если бы вы разрабатывали в классическом ASP, я бы согласился, но ASP.NET/IIS справляется со своей задачей гораздо лучше.

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

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

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

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

Я думаю, что в этом случае можно использовать объект 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.");
}

Краткосрочная информация, которая должна храниться только до следующего запроса, также может храниться в ViewState.Это означает, что объекты сериализуются и сохраняются на странице, отправляемой в браузер, которая затем отправляется обратно на сервер при событии щелчка или аналогичном событии.Тогда ViewState декодируется и снова превращается в объекты, готовые к извлечению.

Сеансы не являются злом, они выполняют важную функцию в приложении ASP.NET, предоставляя данные, которые должны совместно использоваться несколькими страницами во время «сеанса» пользователя.Есть несколько предложений: я бы посоветовал использовать управление сеансами SQL, когда это возможно, и убедиться, что объекты, которые вы используете в своей коллекции сеансов, являются «сериализуемыми».Лучше всего использовать объект сеанса, когда вам абсолютно необходимо обмениваться информацией о состоянии между страницами, и не использовать его, когда в этом нет необходимости.Информация не будет доступна на стороне клиента. Ключ сеанса хранится либо в файле cookie, либо через строку запроса, либо с использованием других методов в зависимости от того, как он настроен, а затем объекты сеанса доступны в таблице базы данных ( если вы не используете InProc, в этом случае ваши сеансы могут быть снесены во время перезагрузки сайта или станут практически бесполезными в большинстве кластерных сред).

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

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

Сессия как зло:Не в ASP.NET, правильно настроен.Да, идеально быть как можно более безгражданством, но реальность такова, что отсюда туда не добраться.Однако вы можете заставить сеанс вести себя так, чтобы уменьшить его влияние — особенно StateServer или сеансы базы данных.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top