我有奇怪的行爲,無法在本地機器上覆制,它開始讓我瘋了。控制器動作被調用兩次,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