ASP.NET MVC 4:一次只允许一个请求

时间:2014-06-20 15:18:30

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

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

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

编辑:该应用程序更像是通过Web执行Web服务调用并清理数据库的批处理/服务。站点中的不同URL导致不同的批处理操作。这不是最终用户的网站。因此,我需要这样做,以便一次只能完成一个URL请求(它将执行一些批处理操作),否则如果代码与其自身或其他批处理操作同时运行,则批处理操作可能会损坏。事实上,如果另一个请求在当前正在执行时发出,则它应该根本不运行,即使在前一个请求完成之后也是如此;它应该只是给出一条错误信息。

我想知道是否有办法在IIS而不是代码中执行此操作。如果我有一个全局锁变量,它会使代码更复杂,我可能会在死锁中运行,其中lock变量设置为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,导致不再提供请求?

2 个答案:

答案 0 :(得分:4)

您尽可能接受请求,人们不喜欢在浏览器前等待。 但之后,在服务方面,yuo可以将它们推入(比如说)Queue<T>并按顺序处理它们。

简而言之:

  • 以异步方式接受
  • 进程,在服务器上,按顺序

答案 1 :(得分: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();
    }
}