Блокировка страницы в asp.net для пользователя - PullRequest
3 голосов
/ 29 августа 2011

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

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

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

Ответы [ 7 ]

2 голосов
/ 31 августа 2011

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

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

2 голосов
/ 29 августа 2011

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

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

2 голосов
/ 29 августа 2011

Я думаю, что это действительно плохая идея по всем упомянутым вами причинам, но если бы у меня было , чтобы сделать это, я бы использовал 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.Таким образом, вы получаете все это бесплатно.

1 голос
/ 22 декабря 2011

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

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

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

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

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

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

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

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

1 голос
/ 31 августа 2011

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

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

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

1 голос
/ 29 августа 2011

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

0 голосов
/ 29 августа 2011

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

...