2013-01-22 13 views
7

Sto scrivendo un'applicazione asp.net 4.5 utilizzando le nuove funzionalità di routing. Ho una pagina che mostra alcune informazioni su un oggetto. Nell'evento Page_Load, controllo i dati del percorso (ID oggetto) e le autorizzazioni utente e, se qualcosa non va bene (ad esempio, l'id è per un elemento eliminato) Io uso Response.RedirectToRoute per inviarlo a pacco, direttamente alla home page. Non passare GO, non raccogliere $ 200.Modo corretto per saltare l'esecuzione della pagina dopo Response.RedirectToRoute

Questo ha perfettamente senso fino a quando non ho provato ad accedere a un elemento eliminato e invece della pagina iniziale ho ricevuto una pagina di errore. Ho fatto un po 'di scavo e ho scoperto che anche dopo aver usato RedirectToRoute (a differenza del metodo standard Redirect) il resto del codice di pagina continues to execute, che per lo meno sembra dispendioso (dato che sto per buttare via i risultati) e genera errori quando i dati necessari non esistono.

Ho fatto un po 'più SO mining e ho scoperto l'incredibile evil che è Response.End(). Fa quello che mi serve, ma anche l'MSDN page mi dice che Response.End è il figlio bastardo di un'antica lingua maledetta e non è adatto a vedere la luce del giorno. L'obiezione principale sembra essere il fatto che Response.End lancia un'eccezione, e questo è male per le prestazioni. Non sono lo sviluppatore più esperto, quindi non capisco completamente il problema, ma ho difficoltà a credere che il lancio di un'eccezione sia più costoso del caricamento dell'intera pagina web. Il workarounds sembra piuttosto complesso ed eccessivo per un compito così semplice, soprattutto perché la maggior parte delle pagine richiede un qualche tipo di controllo di validità.

Cosa dovrei fare in questa situazione? Usa Response.End e chiedi perdono per la mia insolenza? Cobble insieme qualche brutto trucco? Oppure la mia prospettiva sul problema è del tutto sbagliata per cominciare? Mi piacerebbe davvero saperlo.

Aggiornamento: Ora che ci ho pensato un po 'di più, mi chiedo se ho una prospettiva sbagliata sul problema. Forse un reindirizzamento immediato non è la migliore risposta per l'esperienza dell'utente. Farei meglio a confezionare tutti i controlli in un pannello e usare qualcosa di simile?

Private Sub Page_Init(sender As Object, e As EventArgs) Handles Me.Init 
    'Validation Code 
    If notValid Then 
     ControlsPanel.Visible = false 
     ErrorPanel.Visible = true 
    End If 
End Sub 

risposta

3

È probabile che stia uscendo su un arto non rispondendo direttamente alla domanda, ma mi è piaciuto vedere l'aggiornamento relativo all'esperienza dell'utente. Preferisco il tuo approccio suggerito.

Vorrei dare un errore di 410 per id che non sono validi ed estendere un po 'con (tradotto da C#):

Protected Sub ItemDoesNotExist() 
'item does not exist, serve up error page 
ControlsPanel.Visible = False 
ErrorPanel.Visible = True 

'add meta tags for noindex 
Dim mymeta As New HtmlMeta() 
mymeta.Name = "robots" 
mymeta.Content = "noindex" 
Page.Header.Controls.Add(mymeta) 

'RESPOND WITH A 410 
Response.StatusCode = 410 
Response.Status = "410 Gone" 
Response.StatusDescription = "Gone" 
Response.TrySkipIisCustomErrors = True 
'important for IIS7, otherwise the Custom error page for 404 shows. 
Page.Title = "item gone" 
End Sub 
+0

Grazie per il follow su. Non avevo capito che si poteva rispondere con un codice di errore e caricare ancora la pagina. Lo terrò sicuramente a mente in futuro. –

9

RedirectToRoute è in realtà avvolge Response.Redirect passando false per terminare la richiesta - quindi, la richiesta continua. È possibile utilizzare HttpApplication.CompleteRequest come chiamata immediata per terminare la richiesta in modo che gli eventi dell'applicazione successiva non vengano richiamati.

Response.End (e altre variazioni reindirizzamento) tiri ThreadAbortException interrompere il filo richiesta di elaborazione che è davvero una cattiva modo per interrompere l'elaborazione della richiesta. Nel mondo .NET, l'elaborazione delle eccezioni è sempre considerata dispendiosa perché CLR deve quindi cercare fino allo stack per i blocchi di elaborazione delle eccezioni, creare traccia stack ecc. IMO, CompleteRequest è stato introdotto in .NET 1.1 per evitare lo stesso che effettivamente si basa sull'impostazione del flag nel codice dell'infrastruttura ASP.NET per saltare ulteriori elaborazioni eccetto l'evento EndRequest.

Un altro (e migliore) metodo è utilizzare Server.Transfer ed evitare il round-trip del cliente per impostare il reindirizzamento tutti insieme. L'unico problema è che il client non vedrebbe l'URL reindirizzato nella barra degli indirizzi del browser. Io di solito preferisco questo metodo.

EDIT
CompleteRequest non avrebbe mai funzionato nel caso in pagina in cui eventi successivi pagina sarebbe ancora richiamati perché la pagina di essere un gestore, tutti i suoi eventi accade all'interno di un singolo (e attuale) eventi applicazioni ProcessRequest.Così unico modo sembra essere impostando un flag e verificare che bandiera sostituzioni come Render, PreRender, RaisePostBackEvent ecc

Dalla prospettiva manutenzione, senso avere tale funzionalità in classe pagina di base (cioè il mantenimento della bandiera, offerta CompleteRequest metodo per sottoclassi e sovrascrittura dei metodi di eventi del ciclo di vita). Ad esempio,

internal class PageBase: System.Web.UI.Page 
{ 
    bool _requestCompleted; 

    protected void CompleteRequest() 
    { 
     Context.ApplicationInstance.CompleteRequest(); 
     _requestCompleted = true; 
    } 

    protected override void RaisePostBackEvent(IPostBackEventHandler sourceControl, 
    string eventArgument) 
    { 
     if (_requestCompleted) return; 
     base.RaisePostBackEvent(sourceControl, eventArgument); 
    } 

    protected internal override void Render(HtmlTextWriter writer) 
    { 
     if (_requestCompleted) return; 
     base.Render(writer); 
    } 

    protected internal override void OnPreRender(EventArgs e) 
    { 
     if (_requestCompleted) return; 
     base.OnPreRender(e); 
    } 

    ... and so on 
} 
+1

Grazie per la risposta. Ho notato che 'CompleteRequest' è stato proposto come opzione migliore, ma continua anche a eseguire tutto il codice sulla pagina. I vari controlli della pagina ottengono i loro dati dall'elemento e quando non esiste generano errori, quindi ricevo una pagina di errore anziché un reindirizzamento. Potrei passare e verificare la validità di ogni metodo, ma ciò sembra _rather_ inutile e meno mantenibile. –

+0

Trovo interessante che tu menzioni "Server.Transfer". Anche se apprezzo il vantaggio di evitare un viaggio di andata e ritorno, non credo che quel metodo funzionerebbe bene per i miei scopi, poiché l'URL corrente dell'utente non è valido. Ho anche letto che 'Server.Transfer' chiama' Response.End' e non vedo un sovraccarico della funzione per evitare questo. –

+2

@probackpacker, si prega di accettare le mie scuse! 'CompleteRequest' influisce sugli eventi della pipeline dell'applicazione, ma l'evento di gestore corrente potrebbe continuare. Non ci sarebbe altro modo che usare flag per controllare all'interno della pagina - dal punto di vista della manutenzione, è possibile estrarlo in una classe di pagina di base riutilizzabile (vedi la mia modifica). – VinayC