2012-07-20 39 views
7

Tengo un comportamiento extraño, que no se puede replicar en la máquina local y está empezando a volverme loco.La acción del controlador se llama dos veces y los registros de IIS no muestran que

Parece que ASP.NET MVC está tratando de ejecutar acciones, algo se agota, falla sin excepción y avisa al cliente ajax, luego intenta volver a ejecutar la acción, el cliente ajax obtiene respuesta, pero no de la llamada original.

que tienen una acción de controlador:

[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)) 
} 

Y me llaman usando 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 
       } 
      }); 

Y para los pequeños pedidos que trabaja muy bien, pero para las grandes órdenes de dos de creación y diseño razón parece ser el tiempo de procesamiento, cuanto más grande es el orden, más tiempo toma ubicarlo en un servicio web externo.

He comprobado los registros de IIS, para asegurarme de que el script del cliente no llame dos veces a la acción, y los registros de IIS muestran solo una llamada a una acción en particular.

El servicio externo no falla, no hay excepciones registradas en el registro de eventos/registro de sql.

Para asegurarse de que el cliente recibe la respuesta Ajax no de la llamada original que he hecho tipo de bloqueo:

[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(); 
    } 
} 

Y en lugar de devolver los datos confirmados, devuelve "ya poner orden".

he pensado tal vez los tiempos de espera de ejecución de la acción, pero he tratado sólo por el bien

<httpRuntime executionTimeout="600" /> 

no ayudó.

¿Alguna idea de dónde buscar un motivo, qué verificar además, para habilitar el registro adicional?

Actualización: Lo interesante es que esa llamada original también se completó.

Actualización 2: He añadido filtro de acción AjaxOnly para estar seguro, que se llama sólo de 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."); 
     } 
    } 
} 

Y a partir de los registros que se llama sólo desde Javascript, por lo que el misterio continúa ...

actualización 3:

he aislado a un problema sencillo sueño de rosca en el controlador de prueba por separado:

[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); 
    } 

Mientras funcione bien en dos máquinas de desarrollo independientes (win 7) y en la máquina de etapas en ec2 (win2008sp2), es casi seguro un problema con la configuración IIS del servidor de producción (win 2008R2 x64 sp1).

+0

Use asincrónico para llamadas largas que pueden agotar el tiempo de espera. Puede agregar un token de cancelación. Ver mi tutorial http://www.asp.net/mvc/tutorials/mvc-4/using-asynchronous-methods-in-aspnet-mvc-4 – RickAndMSFT

Respuesta

0

encontramos.

Como he empezado a pensar, que es de alguna manera la configuración de IIS involded a esto, he comenzado un nuevo sitio de prueba en la producción de IIS, simplemente por defecto sitio mvc con 90 segundos de espera de hilo
Y funcionó como se supone.
Así que he copiado todo el sitio de producción para ejecutar en diferentes puertos, pensando que podré probar ideas más rápido sin afectar el sitio de producción, y cuando estaba funcionando en un puerto diferente no hubo ningún problema.

Resulta que estábamos usando el equilibrador Amazon Elastic y ese era el problema.

Moral es que hubiera desperdiciado mucho menos tiempo si hubiera estado aislando agresivamente el problema desde el principio.

0

es la sugerencia de una pregunta similar:?

"¿Hay algún otro marcado que podría estar haciendo referencia a la página accidentalmente referencias Script, referencias a imágenes, referencias CSS, todos podrían ser erróneamente señalado en ''. o la página actual."

MVC controller is being called twice

+0

Lo he visto, pero no es así porque) iis logs aún mostraría 2 llamadas b) llamaría dos veces para todas las órdenes, no solo las grandes c) he agregado filtro para permitir que se llame a la acción desde ajax – Giedrius

Cuestiones relacionadas