[英]ASP.NET MVC 4: Only allow one request at a time
In my ASP.NET MVC Application, I want to handle all requests sequentially;在我的 ASP.NET MVC 应用程序中,我想按顺序处理所有请求; no action/controller code should be executed concurrently with another.任何动作/控制器代码都不应与另一个同时执行。 If two requests come in at similar times, it should run the first one first, then the second one when the first one is done.如果两个请求在相似的时间进入,它应该先运行第一个,然后在第一个完成后运行第二个。
Is there a better way of doing this besides using a global lock variable?除了使用全局锁变量之外,还有更好的方法吗?
EDIT: The application is more of a batch/service over the web that performs web service calls and cleans up a database.编辑:该应用程序更像是 Web 上的批处理/服务,用于执行 Web 服务调用和清理数据库。 Different URLS in the site lead to different batch operations.站点中不同的 URL 导致不同的批处理操作。 This is not a site for end-users.这不是面向最终用户的站点。 Thus, I need to make it so that only one request to a URL (which will do some batch operations) will be done at a time, otherwise the batch operation could be corrupted if code for it runs concurrently with itself, or other batch operations.因此,我需要这样做,以便一次只完成一个对 URL 的请求(将执行一些批处理操作),否则,如果批处理操作的代码与其自身或其他批处理操作同时运行,则可能会损坏批处理操作. In fact, if another request comes when one is currently executing, it should not be run at all, even after the previous one finishes;事实上,如果另一个请求在当前正在执行时出现,它根本不应该运行,即使是在前一个请求完成之后; it should just give an error message.它应该只给出一个错误信息。
I would like to know if there was a way to do this in IIS instead of code.我想知道是否有办法在 IIS 而不是代码中做到这一点。 If I have a global lock variable, it would make the code more complicated, and I might run in a deadlock where the lock variable is set to true but never can be set to false.如果我有一个全局锁变量,它会使代码更复杂,我可能会在死锁中运行,锁变量设置为 true 但永远不能设置为 false。
EDIT: Sample code of implementation plan编辑:实施计划的示例代码
[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();
}
Would I need to be worried about a case where the code does not reach Config.Lock = false, resulting in Config.Lock = true forever, causing no more requests to be served?我是否需要担心代码没有达到 Config.Lock = false 的情况,导致 Config.Lock = true 永远,导致不再提供更多请求?
You have accept request as much as you can, people don't like waiting in front of browser. 您已尽可能接受请求,人们不喜欢在浏览器前等待。 But after , on serve side, yuo can push them into (say) Queue<T>
and process them in sequence. 但是,在发球后 ,您可以将它们推入(例如) Queue<T>
并按顺序处理它们。
In short: 简而言之:
You could write an attribute: 您可以编写一个属性:
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);
}
}
then use it on the controllers/methods that you want to control: 然后在要控制的控制器/方法上使用它:
[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();
}
}
the above code does not work probably because when request 1 is running and send request 2, app return service unavailable, it's good but if request 1 doesn't completed and again send request 2 to app, app running both request at same time.上面的代码不起作用可能是因为当请求 1 正在运行并发送请求 2 时,应用程序返回服务不可用,这很好但是如果请求 1 没有完成并再次将请求 2 发送到应用程序,应用程序同时运行两个请求。 I'm reviewed code and change it.我审查了代码并对其进行了更改。
[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);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.