2012-07-20 36 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