2014-11-27 9 views
16

Ho i seguenti controller:Perché il mio metodo di azione non scade?

[TimeoutFilter] 
public abstract class BaseController: Controller 
{ 
} 

public class IntegrationTestController : BaseController 
{ 
    [HttpGet] 
    public ActionResult TimeoutSeconds() 
    { 
     return Content(HttpContext.Server.ScriptTimeout.ToString(CultureInfo.InvariantCulture)); 
    } 

    [HttpGet] 
    public ActionResult ForceTimeout() 
    { 
     var timeoutWindow = TimeoutFilter.TimeoutSeconds; 
     Thread.Sleep((timeoutWindow + 5) * 1000); 
     return Content("This should never get returned, mwahahaaa!"); 
    } 
} 

Per il mio scenario di test che uso un ambiente di configurazione di 5 secondi nel TimeoutFilter, e so che questo funziona perché quando il mio chiamate di prova TimeoutSeconds, ottengo il valore corretto di 5, ma quando il test chiama ForceTimeout, ottengo una risposta HTTP di 200 e il mio testo "mai restituito".

E il filtro:

public class TimeoutFilter : ActionFilterAttribute 
{ 
    internal const string TimeoutSecondsSettingsKey = "MvcActionTimeoutSeconds"; 
    internal static int TimeoutSeconds; 
    public TimeoutFilter() 
    { 
     TimeoutSeconds = int.Parse(ConfigurationManager.AppSettings[TimeoutSecondsSettingsKey]); 
    } 

    public override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     filterContext.Controller.ControllerContext.HttpContext.Server.ScriptTimeout = TimeoutSeconds; 
     base.OnActionExecuting(filterContext); 
    } 
} 
+0

Potete fornire l'implementazione del filtro di timeout? –

+0

@JalpeshVadgama Aggiunto, come richiesto. – ProfK

risposta

7

non ho potuto ottenere questo lavoro impostando la proprietà ScriptTimeout sia, anche quando l'impostazione del debug="false" nella web.config come suggerito dall'utente Erik Funkenbusch:

<configuration> 
    <system.web> 
     <compilation debug="false" targetFramework="4.5"/> 
     ... 

Ha continuato a restituire il testo "Questo non dovrebbe mai essere restituito" piuttosto che il timeout durante lo Thread.Sleep.

Vale anche la pena notare che ho anche esteso lo oltre il valore predefinito di Server.ScriptTimeout di 110 secondi, ma alla fine ha restituito lo stesso testo piuttosto che il timeout.

Poi ho invece cercato di impostare executionTimeout nel web.config:

<configuration> 
    <system.web> 
     <httpRuntime targetFramework="4.5" executionTimeout="5"/> 
     ... 

Se si dovesse aggiungere ora un punto di interruzione alla TimeoutFilter si potrà osservare che il valore ScriptTimeout è stato impostato il valore executionTimeout da web.config. Ahimè, questo ancora non ha funzionato per me (indipendentemente dal fatto che sia debug="false").

Mi sono imbattuto in this link su ScriptTimeout e executionTimeout non funziona con una configurazione simile a ciò che descrivi. La prima risposta nel post descrive l'utilizzo dello debug="false" e menziona anche che il timeout avrà un ritardo compreso tra 5 e 15 secondi. Non ho ancora avuto fortuna nemmeno quando ho usato un grande valore Thread.Sleep. La seconda risposta in questo articolo suggerisce che l'impostazione di configurazione executionTimeout sostituisce la proprietà ScriptTimeout (che è apparentemente un'interfaccia COM utilizzata in ASP classico). Questa risposta suggerisce che non è possibile impostare un timeout specifico senza utilizzare la propria logica di timeout.

Inoltre, mi sono imbattuto nello following (more recent) link dove la prima risposta suggerisce che il timeout è disattivato in MVC. Un'ulteriore risposta suggerisce che questo è dovuto al fatto che uno MVCHandler (che seleziona il controller che gestirà il HTTPRequest) è un IHttpAsyncHandler e come potrebbe quindi eseguire un'altra richiesta (che è il punto di utilizzo di una richiesta asincrona) quindi passa internamente il tempo -out state off (questo è ciò che deduco leggendo questo link). Deve funzionare direttamente con asp.net anche se l'utilizzo di ScriptTimeout sembra essere il modo accettato in this answer.

Il legame suggerisce che aggiungendo la seguente riga permetterà di lavorare (ma non in un'applicazione fiducia media):

System.Web.HttpContext.Current.GetType().GetField("_timeoutState", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).SetValue(System.Web.HttpContext.Current, 1); 

Pertanto, cambiando il TimeoutFilterOnActionExecuting() a:

public override void OnActionExecuting(ActionExecutingContext filterContext) 
{ 
    System.Web.HttpContext.Current.GetType().GetField("_timeoutState", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).SetValue(System.Web.HttpContext.Current, 1); 
    base.OnActionExecuting(filterContext); 
} 

e impostazione web.config:

<configuration> 
    <system.web> 
     <compilation debug="false" targetFramework="4.5"/> 
     <httpRuntime targetFramework="4.5" executionTimeout="5"/> 
     ... 

consente al timeout di funzionare ma ha il leggero ritardo di 5 secondi menzionato nel primo post.

Nota: L'utilizzo di questo metodo non consente di impostare la proprietà ScriptTimeout nel filtro. Cercando di impostare ScriptTimeout e sovrascrivere il valore impostato in web.config non sembra funzionare.

+0

In effetti, buon lavoro da investigatore. Inoltre, ho trovato questo rapporto di connessione, che suggerisce una soluzione alternativa (non molto buona, ma se riesci a farlo funzionare, è meglio di niente) https://connect.microsoft.com/VisualStudio/feedback/details/781171/ asp-net-MVC-executionTimeout-fa-non-lavoro –

6

Si sta utilizzando una build di debug?

Dalla documentazione ScriptTimeout:

http://msdn.microsoft.com/en-us/library/system.web.httpserverutility.scripttimeout(v=vs.110).aspx

Se si imposta l'attributo debug dell'elemento compilation su true nel file web.config, verrà ignorato il valore di ScriptTimeout.

Inoltre, dal momento che questo valore è lo stesso di quello impostato sul elemento httpRuntime, io davvero non capisco il senso di questo, dal momento che si può solo configurare tale impostazione nel web.config, invece.

Edit:

Pericoloso ha fatto un buon lavoro di scoprire i dettagli, e in effetti, ScriptTimeout è supportato in tubazioni asincroni (che MVC è stato almeno dal MVC4 credo, così come WebAPI .. anche se non con metodi asincroni)

la "soluzione alternativa", come suggerito da questo rapporto di connessione:

https://connect.microsoft.com/VisualStudio/feedback/details/781171/asp-net-mvc-executiontimeout-does-not-work

utilizzare il [AsyncTimeout] att ributare e prendere un token di annullamento come parametro, quindi chiamare periodicamente CanclationToken.ThrowIfCancelationRequested oppure utilizzare il token di cancellazione in un metodo asincrono.

Ecco un esempio:

[AsyncTimeout(5000)] 
public async Task<ContentResult> Index(CancellationToken ct) 
{ 
    await Task.Delay(10 * 1000, ct); 
    return Content("This should never get returned, mwahahaaa!"); 
} 

Questo genera un'eccezione OperationCanceled con un YSOD dopo 5 secondi. Il bonus per questo è che funziona anche in modalità debug;)

+0

Non sono sicuro di quale sia il valore finale di configurazione, dopo alcune letture su 'machine.config' che sovrascrivono il valore, e 'machine' è un sito Web di Azure. In questo modo posso insistere su un determinato valore di timeout. – ProfK

+1

@ProfK - Perché hai pubblicato un premio quando ti ho dato la risposta? –

+0

Erik, come note pericolose di cui sopra, la modifica dell'attributo 'debug' non ha alcun effetto, da solo. – ProfK

Problemi correlati