【问题标题】:ASP.NET MVC 4: Only allow one request at a timeASP.NET MVC 4:一次只允许一个请求
【发布时间】:2022-01-05 18:56:08
【问题描述】:

在我的 ASP.NET MVC 应用程序中,我想按顺序处理所有请求;任何动作/控制器代码不应与另一个同时执行。如果两个请求同时进入,它应该先运行第一个,然后在第一个完成后运行第二个。

除了使用全局锁变量之外,还有更好的方法吗?

编辑:该应用程序更像是 Web 上的批处理/服务,它执行 Web 服务调用并清理数据库。站点中不同的 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 永远,导致不再提供请求?

【问题讨论】:

  • 向我们展示你目前拥有的东西怎么样?

标签: c# asp.net-mvc request sequential controller-action


【解决方案1】:

您尽可能多地接受请求,人们不喜欢在浏览器前等待。 但是之后,在服务端,你可以将它们推送到(比如)Queue<T> 并按顺序处理它们。

简而言之:

  • 以异步方式接受
  • 在服务器上按顺序处理

【讨论】:

    【解决方案2】:

    你可以写一个属性:

    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();
        }
    }
    

    【讨论】:

    • 在我接受这个答案之前,考虑到所有可能的情况,如异常、网络故障等,此代码是否会导致 isExecuting = 1 且不能设置为 0 的“死锁” 、停电、程序崩溃等?
    • @user3760689 :我不确定。我建议在使用它之前进行一些测试。
    • 最终使用了这种方法,但使用 try/catch 块来处理异常并将锁定值设置回 0。
    【解决方案3】:

    上面的代码不起作用可能是因为当请求 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);
            }
    

    【讨论】:

      猜你喜欢
      • 2010-12-12
      • 1970-01-01
      • 2017-02-26
      • 1970-01-01
      • 2021-11-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多