ASP.NET MVC 4: разрешать только один запрос за раз

В моем приложении ASP.NET MVC я хочу обрабатывать все запросы последовательно; код действия / контроллера не должен выполняться одновременно с другим. Если два запроса поступают в одно и то же время, сначала он должен выполнить первый, а затем второй, когда первый будет выполнен.

Есть ли лучший способ сделать это, кроме использования глобальной переменной блокировки?

РЕДАКТИРОВАТЬ: приложение представляет собой больше пакет / сервис через Интернет, который выполняет вызовы веб-сервисов и очищает базу данных. Различные URL-адреса на сайте приводят к различным пакетным операциям. Это не сайт для конечных пользователей. Таким образом, мне нужно сделать так, чтобы за один раз выполнялся только один запрос к URL (который будет выполнять некоторые пакетные операции), в противном случае пакетная операция может быть повреждена, если код для нее выполняется одновременно с самим собой или другими пакетными операциями., Фактически, если другой запрос приходит, когда он выполняется в данный момент, он не должен выполняться вообще, даже после того, как предыдущий завершается; это должно просто дать сообщение об ошибке.

Я хотел бы знать, если бы был способ сделать это в IIS вместо кода. Если бы у меня была глобальная переменная блокировки, это усложнило бы код, и я мог бы работать в тупике, где переменная блокировки установлена ​​в значение true, но никогда не может быть установлена ​​в false.

РЕДАКТИРОВАТЬ: Образец кода плана реализации

[HttpPost]
public ActionResult Batch1()
{
    //Config.Lock is a global static boolean variable
    if(Config.Lock) { Response.Write("Error: another batch process is running"); return View(); }
    Config.Lock = true; 

    //Run some batch calls and web services (this code cannot be interleaved with ExecuteBatchCode2() or itself)
    ExecuteBatchCode();

    Config.Lock = false;
    return View();
}

[HttpPost]
public ActionResult Batch2()
{
    if(Config.Lock) { Response.Write("Error: another batch process is running"); return View(); }
    Config.Lock = true;

    //Run some batch calls and web services (this code cannot be interleaved with ExecuteBatchCode1() or itself)
    ExecuteBatchCode2();

    Config.Lock = false;
    return View();
}

Должен ли я беспокоиться о случае, когда код не достигает Config.Lock = false, что приводит к Config.Lock = true навсегда, что приводит к тому, что больше нет запросов на обслуживание?

3 ответа

Решение

Вы можете написать атрибут:

public class ExclusiveActionAttribute : ActionFilterAttribute
{
    private static int isExecuting = 0;
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (Interlocked.CompareExchange(ref isExecuting, 1, 0) == 0)
        {
            base.OnActionExecuting(filterContext);   
            return; 
        }
        filterContext.Result = 
            new HttpStatusCodeResult(HttpStatusCode.ServiceUnavailable);
    }

    public override void OnResultExecuted(ResultExecutedContext filterContext)
    {
        base.OnResultExecuted(filterContext);
        Interlocked.Exchange(ref isExecuting, 0);
    }
}

затем используйте его на контроллерах / методах, которыми вы хотите управлять:

[ExclusiveAction] //either here, for every action in the controller
public class MyController : Controller
{
    [ExclusiveAction] //or here for specific methods
    public ActionResult DoTheThing()
    {
        //foo
        return SomeActionResult();
    }
}

Вы принимаете запрос столько, сколько можете, людям не нравится ждать перед браузером. Но после, на стороне подачи, вы можете подтолкнуть их (скажем) Queue<T> и обработать их в последовательности.

Короче:

  • принять в асинхронном режиме
  • процесс, на сервере, в последовательности

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

         [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
    public class ExclusiveActionAttribute : ActionFilterAttribute
    {
        private static int _isExecuting = 0;
        private static int _isDuplicated = 0;
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            if (Interlocked.CompareExchange(ref _isExecuting, 1, 0) == 0)
            {
                base.OnActionExecuting(filterContext);
                return;
            }

            Interlocked.Exchange(ref _isDuplicated, 1);
            filterContext.Result = new StatusCodeResult((int)HttpStatusCode.ServiceUnavailable);
        }

        public override void OnResultExecuted(ResultExecutedContext filterContext)
        {
            base.OnResultExecuted(filterContext);
            if (_isDuplicated == 1)
            {
                Interlocked.Exchange(ref _isDuplicated, 0);
                return;
            }
            Interlocked.Exchange(ref _isExecuting, 0);
        }
Другие вопросы по тегам