Блокировка страницы в asp.net для пользователя

Я столкнулся с проблемой блокировки страницы asp.net. У нас есть страница профиля пользователя, на которой нам нужно заблокировать эту страницу для пользователя, который открыл ее первым. Подробности следующие: в базе данных много записей профиля пользователя, и мы передаем номер записи в строку запроса, чтобы открыть определенную страницу. Пользователь нажимает кнопку ссылки в сетке и открывает запись в режиме только для чтения. Существует кнопка редактирования, которая включает все элементы управления и делает ее доступной пользователю после того, как он щелкнет по ней. Задача состоит в том, чтобы заблокировать запись для пользователя, который первым нажимает кнопку редактирования.

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

заранее спасибо

7 ответов

Если вы попытаетесь заблокировать запись, вы на 100% получите устаревшие блокировки, а это значит, что вам потребуется процесс удаления этих устаревших блокировок.

Если вы просто пытаетесь предотвратить одновременное изменение, вы можете сделать это с помощью отметки времени или поля версии. При редактировании записи поместите версию / метку времени в скрытое поле. Затем, при попытке применить обновления, первое, что вы делаете, это перечитываете данные, соответствующие идентификатору, затем проверяете версию, которая возвращается из базы данных, против версии в скрытом поле. Если они совпадают, тогда можно смело применять изменения, а если нет, то вы можете применить некоторую логику, чтобы определить, как действовать дальше.

Для хорошего пользовательского опыта я бы установил сердцебиение на странице после того, как пользователь нажимает "редактировать", используя некоторый JavaScript. Каждые 5 секунд или что-то более разумное, я бы пинговал сервер. Поэтому, если пользователь отключается по какой-либо причине, вы можете довольно быстро снять блокировку, раскрутив поток, который проверяет, когда пользователь последний раз проверял страницу. Вам нужно было бы где-то хранить время пинга, например, кеш сервера или сеанс, но я бы предпочел распределенный кеш, такой как memcache, для балансировки нагрузки (хотя это может быть не важно в вашей среде).

Сама блокировка должна быть достаточно простой для реализации, но я бы предпочел либо решение распределенного кэша, например memcache, либо столбец меток времени в базе данных. Я бы по-прежнему включал безотказное истечение срока действия на тот случай, если оно не истечет через пульс.

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

Итак, как то так:

    Cache.Add(someUniqueKeyForAUserProfile, theUserThatLockedTheRecord, null, 
    DateTime.Now.AddSeconds(120), Cache.NoSlidingExpiration, CacheItemPriority.Normal, 
    UnlockRecord)

    private static void UnlockRecord(string key, object value, CacheItemRemovedReason reason) {
       //This particular record went longer than 2 minutes without 
       //the user doing anything, do any additional cleanup here you like
    }

Затем на странице вы можете сделать что-то вроде:

if (Cache[someUniqueKeyForAUserProfile] != theUserThatLockedTheRecord){
  //Tell the user they can't access the page
}

Приятно, что вы автоматически "разблокируете" запись через две минуты, используя встроенный кеш ASP.NET. Таким образом, вы получаете все это бесплатно.

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

Возможно, сохраните кэшированное значение имени страницы в кэше, в котором хранится запись пользователя, заблокировавшего файл, с истечением, скажем, 10 минут. Если другой пользователь запрашивает файл, ваш код сначала проверяет, находится ли имя страницы в кэше. Если один и тот же пользователь запрашивает один и тот же файл (т. Е. Выполняет обратную передачу или обновление), обновите кэш (т. Е. Сбросьте таймер), и у них будет 10 дополнительных минут. Допустим, пользователь пишет длинное письмо с перегибом, и он не опубликовал или не обновил страницу, и прошло 10 минут, вы можете исправить это, имея таймер на стороне клиента, который срабатывает через 9 минут и предупреждает пользователя "ваше время с страница закроется через 1 минуту, нажмите "ОК", чтобы продлить время еще на 10 минут ".

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

@ Брайан Дрисколл говорит, что они установили немного в записи базы данных. Затем они говорят своим пользователям, что они ДОЛЖНЫ щелкнуть "Сохранить" или "Отменить". В самом деле? Есть так много вещей не так с этим.

Правило 1 дизайна взаимодействия "пользователи" не будет делать то, что вы ожидаете - никогда.

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

Правило 2 блокировок - когда действует правило 1 блокировок, вам нужен out - в частности, TIMEout или какой-либо другой способ освобождения потерянных блокировок.

В WikiPedia много написано о блокировке, которую стоит прочитать. Блокировка файлов и блокировка потоков (мьютексы, семафоры и т. Д.) Действительно похожи на эту проблему, и понимание того, как они работают, является хорошей отправной точкой. Пользователь действительно - это просто еще один внешний параллельный процессор, верно?

@ Майкл Юн, на мой взгляд, дает очень интересный ответ. Мы находимся в процессе реализации именно этого типа блокировки на основе страниц, и это то, что мы делаем сейчас в системе, но мы изменим это, чтобы больше походить на идею Yoon постоянно пинговать сервер, чтобы расширить блокировку.

  1. Пользователь нажимает изменить
  2. Запросить блокировку на предмет, который нужно отредактировать (длительность 5 минут?)
    • На успехе GOTO 3
    • При сбое уведомить пользователя блокировка не получена
  3. Проверьте версию элемента, возвращенную маркером блокировки
    • Если версия такая же (никогда не может быть старше, верно?) GOTO 5
    • Если версия новее, GOTO 4
  4. Получить последнюю версию элемента с сервера
  5. Войдите в режим редактирования
  6. Периодически проверяйте возраст блокировки и уведомляйте пользователя, когда срок действия блокировки истекает

В частности, мы бы заменили пункт 6 идеей Юна не беспокоить пользователя уведомлением, а использовать "длительность микроблокировки", возможно, 30 секунд и поддерживать блокировку активной, увеличивая продолжительность блокировки у клиента чаще, чем на 30 секунд.

Я работал над аналогичной системой, и в нашем случае мы установили немного в записи в базе данных, чтобы указать, что она редактировалась. Однако, в отличие от вашего случая, мы смогли установить для конечных пользователей нашей системы ожидание, что они ДОЛЖНЫ щелкнуть либо "Сохранить", либо "Отмена", чтобы перевернуть бит назад и разрешить редактирование записи другими пользователями. Я, честно говоря, не совсем уверен, как справиться со случаем, когда пользователь покидает страницу, хотя на ум приходит запланированное задание, которое запускает sproc, который освободит запись, если она была заблокирована в течение определенного периода времени. время (это означает, что вам также понадобится поле даты и времени, чтобы указать, когда запись была заблокирована).

Это трудно сделать в Интернете. Я рекомендую использовать метку времени в БД, когда пользователь 1 обращается к данным. Затем дайте User1 способ разблокировать страницу вручную, а также использовать значение тайм-аута, используя TimeStamp для автоматической разблокировки записей для User2, если User1 покидает страницу (отключается, закрывает браузер, теряет интернет-соединение... и т. Д.),

Другие вопросы по тегам