Действие контроллера вызывается дважды, и журналы 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
                }
            });

И для небольших заказов работает нормально,но для больших заказов создаются два заказа, и причина, по-видимому, заключается во времени обработки, чем больше заказ, тем больше времени занимает его размещение на внешнем веб-сервисе.

Я проверил журналы 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);
    }

. Пока он работает нормально на двух независимых машинах разработки (win 7 )и промежуточной машине в ec2 (win2008sp2 ), это почти наверняка проблема с настройками IIS производственного сервера (win 2008R2 x64 sp1 ).

7
задан Giedrius 23 July 2012 в 12:10
поделиться