Подтвердить что ты не робот

Неконфигурируемое хранилище состояний сеанса ASP.NET

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

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

Я использую документацию MSDN для поставщиков состояний сеанса для записи моего собственного поставщика состояния сеанса и этот вопрос SO указал мне на этот примерный код реализации этого как HTTP-модуля, но код выглядит подозрительно сложным только с целью удаления блокировки.

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

Любые идеи или примеры реализации?

4b9b3361

Ответ 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 для его запуска.