我有奇怪的行为,无法在本地机器上复制,它开始让我疯了。控制器动作被调用两次,IIS日志不显示
看起来像ASP.NET MVC试图执行操作,超时,它没有任何异常并通知给ajax客户端,然后尝试重新运行操作,ajax客户端获取响应,但不是从原来的调用。
我有一个控制器的动作:
[ValidateAntiForgeryToken]
[ClientErrorHandler]
public virtual ActionResult PlaceOrder(CheckoutDto checkoutDto)
{
LoadDataFromDatabase();
// this may take up to couple minutes
var orderConfirmationData = PlaceOrderToExternalWebservice();
SaveConfirmationData(orderConfirmationData);
return View(Transform(orderConfirmationData))
}
而且我把它使用jQuery的ajax:
$.ajax({
url: placeOrderActionUrl,
type: "POST",
async: true,
dataType: "html",
data: $('#checkoutForm').serialize(),
success: function (data) {
// show confirmation data
},
error: function (request, status, error) {
// show error message
}
});
而对于小订单,它工作正常,但对于大订单创建和理性两个数量级似乎是处理时间,订单越大,将其放置到外部Web服务需要的时间越长。
我已经检查了IIS日志,以确保客户端脚本不会调用操作两次 - 并且IIS日志只显示一个特定操作的调用。
外部服务不会失败,事件日志/ sql日志中没有记录异常。
要确保,即AJAX客户端获得响应不是从原来的呼叫我做了一种锁:
[ValidateAntiForgeryToken]
[ClientErrorHandler]
public virtual ActionResult PlaceOrder(CheckoutDto checkoutDto)
{
try
{
if (OrderingLockedForCurrentUser())
{
Log("Locked");
return View("Already placing order");
}
LockOrderingForCurrentUser();
LoadDataFromDatabase();
// this may take up to couple minutes
var orderConfirmationData = PlaceOrderToExternalWebservice();
SaveConfirmationData(orderConfirmationData);
return View(Transform(orderConfirmationData))
}
finally
{
RemoveOrderingLockForCurrentUser();
}
}
,而不是返回确认的数据,则返回“已订货”和。
我想,也许动作执行超时,但我试过只是为了
<httpRuntime executionTimeout="600" />
没有帮助。
任何想法在哪里搜索一个原因,还有什么额外的检查,以启用任何额外的日志记录?
更新:有趣的是,原来的电话也完成了。
更新2:我添加了行为过滤AjaxOnly可以肯定,它只是从JavaScript调用:
public class AjaxOnlyAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (!filterContext.HttpContext.Request.IsAjaxRequest())
{
throw new Exception("This action is intended to be called from Ajax only.");
}
}
}
而且从日志它只是从JavaScript调用,所以谜继续...
更新3:
我在单独测试控制器分离的问题简单的线程睡眠:
[ValidateAntiForgeryToken]
[AjaxOnly]
[ClientErrorHandler]
public virtual ActionResult PlaceOrderAction(CheckoutDto checkoutDto)
{
try
{
if (CanPlaceOrder(Request.RequestContext.HttpContext))
{
Thread.Sleep(TimeSpan.FromSeconds(90));
return Content("First time");
}
return Content("Second time");
}
finally
{
HttpContext.Cache.Remove(GetKey(userService.CurrentUser.UserId));
}
}
public bool CanPlaceOrder(HttpContextBase httpContext)
{
var userId = userService.CurrentUser.UserId;
var key = GetKey(userId);
if (httpContext.Cache[key] == null)
{
httpContext.Cache.Add(key, userId, null, DateTime.Now.AddMinutes(10), new TimeSpan(), CacheItemPriority.High, null);
return true;
}
return false;
}
private static string GetKey(int userId)
{
return "PlacingOrder{0}".With(userId);
}
只要它在ec2(win2008sp2)上的两个独立开发机器(win 7)和登台机器上运行正常,生产服务器IIS设置(win 2008R2 x64 sp1)几乎肯定会出现问题。
对可能超时的长时间呼叫使用异步。您可以添加取消令牌。看到我的教程http://www.asp.net/mvc/tutorials/mvc-4/using-asynchronous-methods-in-aspnet-mvc-4 – RickAndMSFT 2012-07-20 15:24:20