как заблокировать действие asp.net mvc?

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

Есть ли встроенный способ блокировки действия asp.net mvc?

благодаря

Вы ищете что-то вроде этого?

public MyController : Controller { private static object Lock = new object(); public ActionResult MyAction() { lock (Lock) { // do your costly action here } } } 

Вышеупомянутое предотвратит выполнение каких-либо других streamов, если stream в настоящее время обрабатывает код в блоке блокировки.

Обновление: вот как это работает

Код метода всегда выполняется streamом. На сильно загруженном сервере можно ввести два или несколько разных streamов и начать параллельный запуск метода. В соответствии с вопросом, это то, что вы хотите предотвратить.

Обратите внимание, что объект private Lock является static . Это означает, что он доступен для всех экземпляров вашего controllerа. Таким образом, даже если в куче есть два экземпляра этого controllerа, оба из них имеют один и тот же объект Lock. (Объекту даже не нужно называть Lock, вы могли бы назвать его Джерри или Самантой, и это все равно будет служить той же цели.)

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

Ключевое слово lock можно использовать для предотвращения этого. Когда stream входит в блок кода, завернутый в секцию lock , он «поднимает» объект блокировки (то, что находится в скобках после ключевого слова lock , например Lock , Jerry или Samantha , которое должно быть помечено как static поле). В течение времени, когда выполняется блокировка секции, она «удерживает» объект блокировки. Когда stream выходит из заблокированной секции, он «отказывается» от объекта блокировки. С момента, когда stream захватывает объект блокировки, пока он не отбросит объект блокировки, все другие streamи не смогут войти в заблокированную секцию кода. По сути, они «приостановлены», пока текущий исполняемый stream не отбросит объект блокировки.

Таким образом, stream A захватывает объект блокировки в начале вашего метода MyAction. Прежде чем он откажется от объекта блокировки, stream B также пытается выполнить этот метод. Однако он не может забрать объект блокировки, потому что он уже удерживается streamом A. Таким образом, он ожидает, что stream A откажется от объекта блокировки. Когда это произойдет, stream B затем берет объект блокировки и начинает выполнение блока кода. Когда stream B завершает выполнение блока, он выдает объект блокировки для следующего streamа, который делегирован для обработки этого метода.

… но я не уверен, что это то, что вы ищете …

Использование этого подхода не обязательно сделает ваш код более быстрым. Это гарантирует, что блок кода может выполняться только одним streamом за раз. Обычно он используется по причинам параллелизма, а не по соображениям производительности. Если вы можете предоставить больше информации о своей конкретной проблеме в вопросе, может быть лучший ответ, чем этот.

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

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

 if (!Monitor.TryEnter(Lock, new TimeSpan(0))) { throw new ServiceBusyException("Locked!"); } try { ... } finally { Monitor.Exit(Lock); } 

Используйте тот же статический объект блокировки, как описано @danludwig

Вы можете создать пользовательский атрибут, например [UseLock] согласно вашим требованиям, и поместить его перед своим действием

Самый простой способ сделать это – сохранить в кеше логическое значение, указывающее, что действие уже выполняет требуемый BL:

 if (System.Web.HttpContext.Current.Cache["IsProcessRunning"]) { System.Web.HttpContext.Current.Cache["IsProcessRunning"] = true; // run your logic here System.Web.HttpContext.Current.Cache["IsProcessRunning"] = false } 

Конечно, вы можете сделать это или что-то подобное, как и атрибут.

У меня есть предложения по этому поводу.

1- https://github.com/madelson/DistributedLock решение для системной блокировки

2 – Заставка BackgroundJob.Enqueue с атрибутом [DisableConcurrentExecution (1000)].

Два процесса ожидаются для завершения процесса. я не хочу бросать ошибку при запросе в то же время.

  • Weird Error Обновление ASP.NET MVC с 4 до 5
  • mvc Html.BeginForm другая схема URL
  • Получить controller и имя действия из controllerа?
  • Поддержка optgroup в выпадающем списке .NET MVC?
  • {version} в MVC4 Bundle
  • Должен ли ServiceStack быть служебным слоем в приложении MVC или должен ли он вызвать сервисный уровень?
  • Проверка MVC3 - требуется от группы
  • ASP.NET MVC: для этого объекта не задан конструктор без параметров
  • Загрузка файла MVC 3 и привязка к модели
  • ViewModel со списком и шаблонами редакторов
  • Простой просмотр ASP.NET MVC CRUD при открытии / закрытии в диалоге пользовательского интерфейса JavaScript
  • Давайте будем гением компьютера.