Sto avendo un comportamento strano, che non può replicarsi sulla macchina locale e sta iniziando a farmi impazzire.L'azione del controller viene richiamata due volte ei registri IIS non mostrano che
Sembra ASP.NET MVC sta cercando di eseguire l'azione, qualcosa di timeout, non riesce senza alcuna eccezione e comunicazione al cliente ajax, poi cerca di eseguire nuovamente l'azione, ajax client ottiene risposta, ma non dalla chiamata originale.
ho un azione di controllo:
[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))
}
E mi chiamano utilizzando 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
}
});
E per i piccoli ordini funziona bene, ma per i grandi ordini vengono creati e ragione due ordini sembra essere il tempo di elaborazione, maggiore è l'ordine, maggiore è il tempo impiegato per il webservice esterno.
Ho controllato i registri IIS, per assicurarsi che lo script client non stia chiamando l'azione due volte e che i registri IIS mostrino solo una chiamata a un'azione particolare.
Il servizio esterno non ha esito negativo, non ci sono eccezioni registrate nel registro eventi/log sql.
Per assicurarsi, quel cliente ajax ottiene risposta non dalla chiamata originale che ho fatto tipo di serratura:
[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();
}
}
E invece di tornare informazioni confermate, esso restituisce "già ordinare".
ho pensato che forse azione di esecuzione timeout, ma ho provato solo per amor
<httpRuntime executionTimeout="600" />
non ha aiutato.
Qualche idea su dove cercare un motivo, che altro da controllare, per abilitare qualsiasi registrazione aggiuntiva?
Aggiornamento: Interessante è che anche la chiamata originale è stata completata.
Update 2: ho aggiunto filtro azione AjaxOnly per essere sicuri, che viene chiamato solo da 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.");
}
}
}
E dai registri è chiamato solo da JavaScript, in modo mistero continua ...
Update 3:
ho isolato problema di semplice sonno Discussione in test controller separato:
[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);
}
Finché funziona correttamente su due macchine dev indipendenti (win 7) e una macchina di staging in ec2 (win2008sp2), è quasi certamente un problema con le impostazioni IIS del server di produzione (win 2008R2 x64 sp1).
Utilizzare async per chiamate lunghe che possono scadere. Puoi aggiungere un token di annullamento. Vedi il mio tutorial http://www.asp.net/mvc/tutorials/mvc-4/using-asynchronous-methods-in-aspnet-mvc-4 – RickAndMSFT