2009-11-10 13 views
15

Ho riscontrato un problema con errori personalizzati su un'app di ASP.NET MVC che ho distribuito sul mio host condiviso. Ho creato un ErrorController e aggiunto il seguente codice a Global.asax per rilevare eccezioni non gestite, registrarle e quindi trasferire il controllo a ErrorController per visualizzare errori personalizzati. Questo codice è tratto da here:Pagine di errore personalizzate dell'applicazione ASP.NET MVC non visualizzate nell'ambiente di hosting condiviso

protected void Application_Error(object sender, EventArgs e) 
{ 
    Exception ex = Server.GetLastError(); 
    Response.Clear(); 

    HttpException httpEx = ex as HttpException; 
    RouteData routeData = new RouteData(); 
    routeData.Values.Add("controller", "Error"); 

    if (httpEx == null) 
    { 
     routeData.Values.Add("action", "Index"); 
    } 
    else 
    { 
     switch (httpEx.GetHttpCode()) 
     { 
      case 404: 
       routeData.Values.Add("action", "HttpError404"); 
       break; 
      case 500: 
       routeData.Values.Add("action", "HttpError500"); 
       break; 
      case 503: 
       routeData.Values.Add("action", "HttpError503"); 
       break; 
      default: 
       routeData.Values.Add("action", "Index"); 
       break; 
     } 
    } 

    ExceptionLogger.LogException(ex); // <- This is working. Errors get logged 

    routeData.Values.Add("error", ex); 
    Server.ClearError(); 
    IController controller = new ErrorController(); 
    // The next line doesn't seem to be working 
    controller.Execute(new RequestContext(new HttpContextWrapper(Context), routeData)); 
} 

Application_Error è sicuramente sparare perché la registrazione funziona bene, ma invece di visualizzare le mie pagine di errore personalizzate, ottengo quelli generici Go Daddy. Dal titolo del post sul blog tratto dal codice sopra, ho notato che utilizza Release Candidate 2 del framework MVC. Qualcosa è cambiato in 1.0 che rende l'ultima riga di codice non funziona? Come al solito è works great on my machine.

Qualsiasi suggerimento sarà molto apprezzato.

Modifica: Ho dimenticato di aver provato tutte e 3 le possibilità per la modalità CustomErrors in Web.config (Off, On e RemoteOnly). Stessi risultati indipendentemente da questa impostazione.

Edit 2: E ho anche provato con e senza la decorazione [HandleError] sulle classi Controller.

Aggiornamento: ho capito e risolto il 404s. C'è una sezione del pannello Impostazioni nel Centro di controllo hosting di Go Daddy in cui è possibile controllare il comportamento 404 e l'impostazione predefinita è mostrare la pagina generica, e apparentemente questo sostituisce qualsiasi impostazione di Web.config. Quindi la mia pagina 404 personalizzata ora sta mostrando come previsto. Tuttavia, 500 e 503 non funzionano ancora. Ho codice nella HomeController per afferrare una versione di testo statico del contenuto se SQL Server genera un'eccezione come segue:

public ActionResult Index() 
{ 
    CcmDataClassesDataContext dc = new CcmDataClassesDataContext(); 

    // This might generate an exception which will be handled in the OnException override 
    HomeContent hc = dc.HomeContents.GetCurrentContent(); 

    ViewData["bodyId"] = "home"; 
    return View(hc); 
} 

protected override void OnException(ExceptionContext filterContext) 
{ 
    // Only concerned here with SqlExceptions so an HTTP 503 message can 
    // be displayed in the Home View. All others will bubble up to the 
    // Global.asax.cs and be handled/logged there. 
    System.Data.SqlClient.SqlException sqlEx = 
     filterContext.Exception as System.Data.SqlClient.SqlException; 
    if (sqlEx != null) 
    { 
     try 
     { 
      ExceptionLogger.LogException(sqlEx); 
     } 
     catch 
     { 
      // couldn't log exception, continue without crashing 
     } 

     ViewData["bodyId"] = "home"; 
     filterContext.ExceptionHandled = true; 
     HomeContent hc = ContentHelper.GetStaticContent(); 
     if (hc == null) 
     { 
      // Couldn't get static content. Display friendly message on Home View. 
      Response.StatusCode = 503; 
      this.View("ContentError").ExecuteResult(this.ControllerContext); 
     } 
     else 
     { 
      // Pass the static content to the regular Home View 
      this.View("Index", hc).ExecuteResult(this.ControllerContext); 
     } 
    } 
} 

Ecco il codice che tenta di recuperare il contenuto statico:

public static HomeContent GetStaticContent() 
{ 
    HomeContent hc; 

    try 
    { 
     string path = Configuration.CcmConfigSection.Config.Content.PathToStaticContent; 
     string fileText = File.ReadAllText(path); 
     string regex = @"^[^#]([^\r\n]*)"; 
     MatchCollection matches = Regex.Matches(fileText, regex, RegexOptions.Multiline); 
     hc = new HomeContent 
      { 
       ID = Convert.ToInt32(matches[0].Value), 
       Title = matches[1].Value, 
       DateAdded = DateTime.Parse(matches[2].Value), 
       Body = matches[3].Value, 
       IsCurrent = true 
      }; 
    } 
    catch (Exception ex) 
    { 
     try 
     { 
      ExceptionLogger.LogException(ex); 
     } 
     catch 
     { 
      // couldn't log exception, continue without crashing 
     } 
     hc = null; 
    } 

    return hc; 
} 

Ho verificato che se cambio la stringa di connessione per generare una SqlException, il codice registra correttamente l'errore e quindi cattura e visualizza il contenuto statico. Ma se cambio anche il percorso del file di testo statico in Web.config per testare la versione 503 della Home View, quello che ottengo è una pagina con nient'altro che "servizio non disponibile". Questo è tutto. Nessun messaggio 503 personalizzato con l'aspetto grafico del sito.

Qualcuno ha suggerimenti sui miglioramenti del codice che potrebbero essere utili? Sarebbe utile aggiungere intestazioni diverse a HttpResponse? O è Go Daddy che dirotta pesantemente i 503?

risposta

29

Ho trovato la soluzione ed è incredibilmente semplice. Risulta che il problema era in realtà in IIS7. Durante il debug questo problema in Visual Studio ho visto una proprietà dell'oggetto HttpResponse che non avevo notato prima:

public bool TrySkipIisCustomErrors { get; set; } 

Questo mi ha portato a mio motore di ricerca più vicino che si è un great blog post by Rick Strahl e un altro sul angrypets.com così come this question here on SO. Questi collegamenti spiegano i dettagli scabrosi molto meglio di me, ma questa citazione dal post di Rick cattura abbastanza bene:

La vera confusione qui si verifica perché l'errore viene intercettato da ASP.NET, ma in ultima analisi, poi ancora gestito da IIS che guarda il codice di stato 500 e restituisce la pagina di errore di IIS.

Sembra inoltre che questo comportamento sia specifico per IIS7 in modalità integrata. Da msdn:

durante l'esecuzione in modalità Classic in IIS 7.0 il valore predefinito di proprietà TrySkipIisCustomErrors è vero. Quando si esegue in modalità integrata, il valore predefinito della proprietà TrySkipIisCustomErrors è falso.

Quindi, in sostanza tutto quello che ho finito per dover fare è aggiungere Response.TrySkipIisCustomErrors = true; subito dopo qualsiasi codice che imposta la Response.StatusCode-500 o 503 e tutto ora funziona come previsto.

+1

+1 Grazie, Bryan. Dopo più di 2 ore di ricerca mi hai dato la risposta di cui avevo bisogno. È così semplice. Stavo cercando di impostare un codice di errore 404 che mi stava dando un'eccezione di sicurezza e "Response.TrySkipIisCustomErrors = true;" aggiustato. –

+2

Questo mi stava facendo impazzire. Grazie mille. Inserimento "Response.TrySkipIisCustomErrors = true;" immediatamente dopo aver impostato i codici di risposta nel mio controller degli errori è ciò che ha funzionato per me. Era fuorviante perché la mia istanza locale di IIS 7 stava visualizzando le mie visualizzazioni degli errori personalizzate, ma il server di gestione remota non lo era. = P – NovaJoe

+0

Ero nella stessa barca dopo aver applicato ciò che viene fornito in questa risposta: http://stackoverflow.com/a/7499406/114029. 'Response.TrySkipIisCustomErrors = true;' viene dal cielo! :) –

0

Ospito un sito ASP.NET MVC su GoDaddy e ho riscontrato anche problemi relativi alle pagine di errore personalizzate. Quello che ho trovato, attraverso tentativi ed errori, era che GoDaddy intercettava errori a livello HTTP.

Ad esempio, qualsiasi pagina che ha restituito un codice di stato HTTP di 404 ha causato l'acquisizione della pagina di errore personalizzata di GoDaddy. Alla fine ho cambiato le mie pagine di errore personalizzate per restituire 200 stato e il problema relativo a 404 è andato via. Il mio HTML era lo stesso, solo lo stato HTTP necessario per cambiare.

Non ho mai provato a fare lo stesso con 503 risposte di stato, ma è possibile che la stessa soluzione possa funzionare. Se si cambia da restituire uno stato 503 a 200 stato di ritorno, il problema scompare?

Si noti che, se si esegue questa soluzione alternativa, si desidera impedire ai motori di ricerca di indicizzare le pagine di errore, che una volta quindi restituiscono uno stato 200 non sarà distinguibile (dal punto di vista del motore di ricerca) da una pagina normale. Pertanto, assicurati di aggiungere un tag META ROBOTS per impedire l'indicizzazione delle pagine di errore, ad es.

<META NAME="ROBOTS" CONTENT="NOINDEX"> 

Lo svantaggio di questo approccio può essere che la pagina potrebbe essere rimosso da Google, che non è sicuramente una buona cosa!

UPDATE: Così, in aggiunta, si può anche rilevare se l'agente utente è un crawler o no, e se si tratta di un cingolato restituiscono un 503, mentre se non è un cingolato, restituire un 200. Vedere this blog post per info su come rilevare i crawler. Sì, so che restituire contenuti diversi ai crawler rispetto agli utenti è un no-no SEO, ma l'ho fatto su diversi siti senza alcun effetto negativo finora, quindi non sono sicuro di quale sia il problema.

Fare entrambi gli approcci (META ROBOT e rilevamento bot) può essere la soluzione migliore, nel caso in cui alcuni crawler dispari passino attraverso il bot detector.

+0

Grazie Justin. Alla fine ho capito come risolvere il 404s, vedere il mio aggiornamento sopra. Il problema con questo approccio nella mia situazione è che alcuni dei 503 devono mostrare il messaggio amichevole sulla pagina effettiva in cui il contenuto sarebbe stato. Se restituisco un 200 anziché il 503 e sono abbastanza sfortunato da poter indicizzare i crawler quel giorno, indicheranno il mio messaggio di errore amichevole invece del contenuto corretto. Quindi questo non funzionerà nel mio caso particolare. Grazie per la risposta però. – Bryan

+0

sì, devi fare attenzione ai crawler. Ho notato nel mio post originale che è possibile utilizzare un tag META ROBOT per aggirare questo problema, ma ho aggiunto anche altri dettagli. Vedi sopra. –

+0

Potresti non aver notato effetti negativi, ma non c'è modo di sapere che lo stesso sarebbe valido per me e il mio cliente :-).Sono riluttante a considerare il tuo approccio dal momento che potrebbe causare il mio cliente e, per estensione, essere rimosso e/o bannato dagli indici dei motori di ricerca. – Bryan

Problemi correlati