Pagine di errore personalizzate dell’app ASP.NET MVC che non vengono visualizzate nell’ambiente di hosting condiviso

Sto riscontrando un problema con errori personalizzati su un’app MV.NET di ASP.NET 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 è preso da qui :

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 sta sicuramente sparando perché la registrazione funziona bene, ma invece di visualizzare le mie pagine di errore personalizzate, ottengo quelle di Go Daddy generiche. 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 funziona alla grande sulla mia macchina .

Qualsiasi suggerimento sarà molto apprezzato.

Modifica: Hai dimenticato di dire che ho provato tutte e 3 le possibilità per la modalità customErrors in Web.config (Off, On e RemoteOnly). Stessi risultati indipendentemente da questa impostazione.

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

    Aggiornamento: ho capito e risolto gli 404. C’è una sezione del pannello Impostazioni nel Centro di controllo hosting di Go Daddy in cui è ansible 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 il codice nel 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 qualche suggerimento su miglioramenti al codice che potrebbero aiutare? Sarebbe utile aggiungere intestazioni diverse a HttpResponse? O è Go Daddy che dirotta pesantemente i 503?

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

     public bool TrySkipIisCustomErrors { get; set; } 

    Questo mi ha portato al mio motore di ricerca più vicino che ha pubblicato un ottimo post sul blog di Rick Strahl e un altro su angrypets.com oltre a questa domanda qui su SO . Questi link spiegano i dettagli cruenti molto meglio di me, ma questa citazione dal post di Rick lo cattura molto bene:

    La vera confusione qui si verifica perché l’errore è intrappolato da ASP.NET, ma alla fine è ancora gestito da IIS che controlla il codice di stato 500 e restituisce la pagina di errore di IIS.

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

    Quando si esegue in modalità classica in IIS 7.0, il valore predefinito della proprietà TrySkipIisCustomErrors è true. Quando si esegue in modalità integrata, il valore predefinito della proprietà TrySkipIisCustomErrors è falso.

    Quindi sostanzialmente tutto ciò che ho dovuto fare è aggiungere Response.TrySkipIisCustomErrors = true; subito dopo ogni codice che imposta Response.StatusCode su 500 o 503 e tutto ora funziona come progettato.

    Ospito un sito MVC ASP.NET su GoDaddy e ho anche affrontato 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 la sostituzione 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 è ansible che la stessa mitigazione funzioni. Se si cambia da restituire uno stato 503 a 200 stato di ritorno, il problema scompare?

    Tieni presente che, se esegui questa soluzione alternativa, ti consigliamo di impedire ai motori di ricerca di indicizzare le pagine di errore, che una volta quindi restituiscono uno stato 200 non saranno distinguibili (dal punto di vista del motore di ricerca) da una pagina normale. Quindi assicurati di aggiungere un tag META ROBOTS per impedire l’indicizzazione delle pagine di errore, ad es

      

    Il lato negativo di questo approccio potrebbe essere che la tua pagina potrebbe essere rimossa da Google, il che non è sicuramente una buona cosa!

    AGGIORNAMENTO: Quindi, inoltre, è ansible rilevare se l’agente utente è un crawler o meno, e se è un crawler restituire un 503 mentre se non è un crawler, restituire un 200. Vedere questo post del blog per informazioni su come rilevare 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 dei robot) può essere la soluzione migliore, nel caso in cui alcuni crawler dispari passino attraverso il bot detector.