2013-07-19 10 views
6

Desidero interrompere le azioni richiamate dal metodo jQuery.ajax sul lato server. Posso interrompere la richiesta Ajax utilizzando il metodo $.ajax.abort() sul lato client ma non sul lato server.Come interrompere un'azione in ASP.NET MVC

Aggiornato:

ho usato azione asincrona, invece di azione di sincronizzazione, ma non ho ottenuto quello che voglio! Come sapete, il server non può elaborare più di una richiesta nello stesso momento in cui ciascuna richiesta deve attendere che la precedente sia terminata anche se la richiesta precedente viene annullata dal metodo $ .Ajax.Abort(). So che se uso [SessionState (System.Web.SessionState.SessionStateBehavior.ReadOnly)] lo attribuisco quasi come vorrei ma non mi soddisfa.

Soprattutto voglio interrompere il metodo di elaborazione sul lato server per utente. Questo è tutto :)

+0

Se ho capito bene, non vuoi che XHR colpisca il tuo server? –

+0

:) ... forse qualcosa su queste linee potrebbe aiutare http: // StackOverflow.it/questions/216173/differentiating-between-an-ajax-call-browser-request o http://stackoverflow.com/questions/216173/differentiating-between-an-ajax-call-browser-request –

+2

Grazie, ma non è qualcosa che voglio !! Chiamo un'azione che richiede ad esempio 1 minuto. Voglio consentire agli utenti di annullare la richiesta, se lo desiderano, sto utilizzando $ .ajax.abort() e funziona correttamente e annulla la richiesta, ma so che il server sta lavorando sulla richiesta precedente. Se invio un'altra richiesta con quella sessione sul server, deve attendere fino alla fine dell'ultima azione. –

risposta

4

Si consiglia di guardare con il seguente tipo di controllore Using an Asynchronous Controller in ASP.NET MVC

e anche vedere se questo articolo ti aiuta pure Cancel async web service calls, mi spiace non ho potuto dare alcun esempi di codice questo momento.

Ho creato un esempio come prova di concetto per mostrare che è possibile annullare le richieste lato server. My github async cancel example

Se si stanno chiamando altri siti tramite il codice, sono disponibili due opzioni, a seconda del framework di destinazione e del metodo che si desidera utilizzare. Sono compresi i riferimenti qui per la tua recensione:

WebRequest.BeginGetResponse per l'uso in .Net 4.0 HttpClient per l'uso in .Net 4.5, questa classe ha un metodo per annullare tutte le richieste in sospeso.

Spero che questo ti dia abbastanza informazioni per raggiungere il tuo obiettivo.

+0

Grazie, sono sicuro che mi hai capito bene, potresti mostrarmi un esempio di codice chiaro? –

+2

Facendo qualche ricerca in più potrebbe dipendere da quale versione di mvc stai usando. Giusto per chiarire, la mia comprensione è che ti piacerebbe iniziare una richiesta asincrona, perché è un processo di lunga durata, che gli utenti possono cancellare. Quando l'utente annulla la richiesta, il server afferra quel thread asincrono e sostanzialmente interrompe l'operazione. È corretto? – ermagana

+0

Sì, esattamente! Sto usando ASP.NET MVC 4, non ho lavorato con async in C#, se hai un codice di esempio mi aiuterà! Comunque grazie :) –

-1

Una soluzione semplice è quella di utilizzare qualcosa di simile di seguito. Lo uso per cancellare attività a lungo termine (in particolare generando migliaia di notifiche). Uso lo stesso approccio anche per il progresso dei sondaggi e aggiorno la barra di avanzamento tramite AJAX. Inoltre, questo funziona praticamente su qualsiasi versione di MVC e non dipende da nuove funzionalità di .NET

public class MyController : Controller 
{ 

private static m_CancelAction = false; 

public string CancelAction() 
{ 
    m_CancelAction = true; 
    return "ok"; 
} 

public string LongRunningAction() 
{ 
    while(...) 
    { 
     Dosomething (i.e. Send email, notification, write to file, etc) 

     if(m_CancelAction) 
     { 
      m_CancelAction = false; 
      break; 
      return "aborted"; 
     } 
    } 

    return "ok"; 
} 
} 
+0

Non c'è un rischio per la sicurezza che un altro client possa annullare l'azione di una richiesta a lungo termine da parte del primo cliente. –

0

Abbiamo visto il problema in IE, in cui una richiesta abortito ancora ottenuto trasmesso al azione di controllo - tuttavia, con gli argomenti sono stati rimossi, il che ha portato a errori diversi, riportati nei nostri registri e nelle voci di attività dell'utente.

ho risolto questo utilizzando un filtro come il seguente

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 
using System.Web.Mvc; 
using TWV.Infrastructure; 
using TWV.Models; 

namespace TWV.Controllers 
{ 
    public class TerminateOnAbortAttribute : FilterAttribute, IActionFilter 
    { 
     public void OnActionExecuting(ActionExecutingContext filterContext) 
     { 
      // IE does not always terminate when ajax request has been aborted - however, the input stream gets wiped 
      // The content length - stays the same, and thus we can determine if the request has been aborted 
      long contentLength = filterContext.HttpContext.Request.ContentLength; 
      long inputLength = filterContext.HttpContext.Request.InputStream.Length; 
      bool isAborted = contentLength > 0 && inputLength == 0; 
      if (isAborted) 
      { 
       filterContext.Result = new EmptyResult(); 
      } 
     } 

     public void OnActionExecuted(ActionExecutedContext filterContext) 
     { 
      // Do nothing 
     } 
    } 
} 
3

Ecco un esempio backend:

[HttpGet] 
public List<SomeEntity> Get(){ 
     var gotResult = false; 
     var result = new List<SomeEntity>(); 
     var tokenSource2 = new CancellationTokenSource(); 
     CancellationToken ct = tokenSource2.Token; 
     Task.Factory.StartNew(() => 
     { 
      // Do something with cancelation token to break current operation 
      result = SomeWhere.GetSomethingReallySlow(); 
      gotResult = true; 
     }, ct); 
     while (!gotResult) 
     { 
      // When you call abort Response.IsClientConnected will = false 
      if (!Response.IsClientConnected) 
      { 
       tokenSource2.Cancel(); 
       return result; 
      } 
      Thread.Sleep(100); 
     } 
     return result; 
} 

Javascript:

var promise = $.post("/Somewhere") 
setTimeout(function(){promise.abort()}, 1000) 

Spero di non sono in ritardo.

+0

È possibile utilizzare 'Task.IsCompleted' al posto del flag 'gotResult'? – Simon