2012-07-20 84 views
7

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

+0

對可能超時的長時間呼叫使用異步。您可以添加取消令牌。看到我的教程http://www.asp.net/mvc/tutorials/mvc-4/using-asynchronous-methods-in-aspnet-mvc-4 – RickAndMSFT 2012-07-20 15:24:20

回答

0

發現了它。

正如我開始想,IIS配置以某種方式involded到這一點,我已經開始對生產IIS一個新的測試網站,只是默認MVC網站90分鐘線程睡眠
它的工作原理如下
所以我複製了整個生產站點在不同的端口上運行,認爲我能夠在不影響生產站點的情況下更快地測試想法 - 並且在運行時在不同的港口沒有問題。

原來,我們使用亞馬遜彈性平衡器,這是問題所在。如果我從一開始就侵略性地隔離問題,那麼我會浪費更少的時間。

0

下面是一個類似的問題的建議:

「是否有任何其他標記,可能是偶然引用頁面腳本引用,引用圖像,CSS的引用文件,可能是錯誤的,在指出‘’或當前頁面。「

MVC controller is being called twice

+0

我見過這個,但事實並非如此,因爲)iis日誌仍然會顯示2個調用b)它將調用所有訂單的兩次,不僅是大的c)我已經添加了過濾器以允許從ajax調用操作 – Giedrius 2012-07-20 14:01:04