Неконфигурируемое хранилище состояний сеанса ASP.NET
Я использую хранилище состояний сеанса ASP.NET. Он блокирует доступ к сеансу исключительно, а это означает, что одновременные запросы к одному сеансу обслуживаются последовательно.
Я хочу удалить эту неявную исключительную блокировку, так что несколько запросов за сеанс могут обрабатываться одновременно. Конечно, я сам синхронизирую доступ к состоянию сеанса, где он применим.
Я использую документацию MSDN для поставщиков состояний сеанса для записи моего собственного поставщика состояния сеанса и этот вопрос SO указал мне на этот примерный код реализации этого как HTTP-модуля, но код выглядит подозрительно сложным только с целью удаления блокировки.
Я должен, вероятно, в конечном итоге реализовать состояние сеанса с использованием кеша ASP.NET и прекратить использовать встроенный сеанс, например, Vivek описывает в этот пост, но пока как мне просто хотелось бы удалить блокировку.
Любые идеи или примеры реализации?
Ответы
Ответ 1
Не тот ответ, который вы ищете, но я думаю, что даже если это было возможно, изменение способа работы SessionState таким образом - ужасная идея.
Подумайте о бедных парнях, которым придется поддерживать свой код на линии. Тот факт, что сеанс сериализует запросы таким образом, означает, что разработчикам ASP.NET часто не нужно слишком беспокоиться о безопасности потоков.
Кроме того, если кто-то добавляет сторонний компонент, который использует Session, он будет ожидать обычных гарантий относительно блокировок - и вы вдруг начнете получать Heisenbugs.
Вместо этого измерьте производительность и определите конкретные области, в которых вам понадобятся запросы для обработки одновременно - я уверен, их будет мало - и тщательно внедрите свой собственный механизм блокировки только для определенных элементов - возможно, решение, которое вы используете в конечном итоге, используя кеш ASP.NET.
Ответ 2
Если вы читаете только сеанс на данной странице, вы можете использовать директиву Page
:
<%@ Page EnableSessionState="ReadOnly" %>
чтобы указать характер чтения и удалить исключительную блокировку записи, которая позволит одновременные запросы на эту страницу с того же сеанса.
Как внутренняя блокировка ReaderWriter используется, блокировка чтения блокирует блокировку записи, но блокировка считывателя не блокирует блокировку чтения. Блокировка записи блокирует все блокировки чтения и записи.
Если вам нужно как читать, так и писать с той же страницы на сеанс, я думаю, что то, что вы уже нашли в качестве информации, более чем достаточно. Просто замечание о замене сеанса на кеш: в то время как сеанс является надежным, кеш не означает, что если вы поместите что-то в кеш, вам не гарантируется его возврат. ASP.NET может решить выдворить кеш при некоторых обстоятельствах, таких как низкое давление памяти, поэтому вам всегда нужно проверить, существует ли элемент в кеше, прежде чем обращаться к нему.
Ответ 3
но код выглядит подозрительно сложным только с целью удаления блокировки.
Это потому, что вы думаете об этом как о простой блокировке, которую кто-то добавил случайно или лень, вместо фактора, который рассматривался во всей концепции провайдера сеанса. Этот код выглядит достаточно простым для задачи под рукой/замены всего существующего провайдера на свой собственный/и при этом блокировки другим способом, чем это предусмотрено.
Я предлагаю вам прочитать немного больше о том, как концепция сеанса работает в asp.net. Учтите, что способ, которым он был разработан, включает чтение всего сеанса один раз в запросе, а затем запись измененного сеанса один раз.
Также обратите внимание, что хотя ваш сценарий не является вашим сценарием, код может зависеть от чтения отдельных значений сеанса для обработки чего-либо и может также записывать отдельные значения, а также блокировать индивидуально, чтобы вы могли использовать те же соображения, которые могут вызвать мертвую блокировку в базах данных.
Разработанный способ контрастирует с вашей целью чтения/записи + блокировки, поскольку каждый отдельный элемент загружен/сохранен.
Также обратите внимание, что вы можете обновлять значения объекта, который вы извлекли из сеанса, и не устанавливать его обратно, но сеанс был обновлен. Насколько я знаю, провайдеры пишут все на сессии в определенный момент жизненного цикла, поэтому это не так просто, если вы хотите разделить блокировки чтения и записи на уровне позиций.
Наконец, если вы находите высокий уровень сопротивления из модели поставщиков рамочных сеансов и способ, которым вы намерены его модифицировать, это не позволит вам использовать некоторые функции (как переход на поставщика diff, поскольку у них будет тот же вопрос); то я думаю, вам следует просто держаться подальше от него и закатывать свои собственные для ваших конкретных потребностей. Это, даже не используя asp.net Cache, поскольку вы хотите, чтобы это было вашим путем, вы контролируете время жизни и блокировки того, что там хранится.
Мне просто кажется, что вам нужен совсем другой механизм, поэтому я не вижу смысла пытаться сгибать структуру, чтобы сделать это. Вы можете повторно использовать некоторые очень специфические фрагменты, например, генерировать идентификатор сеанса/и cookie vs. cookie-less, но кроме этого его другого зверя.
Ответ 4
Вам нужно будет написать собственный провайдер состояния сеанса, это не так сложно, как кажется. Я бы не рекомендовал вам использовать Cache, потому что, поскольку Дарин сказал, что кэш недостаточно надежный, например, элементы, которые там истекают и/или удаляются из кеша, когда памяти недостаточно.
В своем провайдере хранилища сеансов вы можете заблокировать элементы сеанса вместо всего состояния сеанса (что подходит нам в нашем проекте) при написании важного кода для этого должен быть в ISessionStateItemCollection
реализации (в индексаторе), примерно так:
public object this[string name]
{
get
{
//no lock, just returning item (maybe immutable, it depends on how you use it)
}
set
{
//lock here
}
}
Для нашего проекта мы создали реализацию, которая хранит элементы в AppFabric Cache и полагается на методы GetAndLock, PutAndUnlock в кеше. Если у вас есть сеанс In-proc, вам может понадобиться lock(smthg) {}
Надеюсь, что это поможет.
Ответ 5
Я предлагаю вам перевести сеансы в режим SQL Server. Сеансы SQL Server позволяют разрешать любое количество запросов от нескольких веб-серверов для совместного использования одного сеанса. Насколько мне известно, SQL Server управляет встроенным механизмом блокировки, который чрезвычайно эффективен. У вас также есть дополнительный бонус с меньшим объемом памяти. И вам не нужно писать HttpModule для его запуска.