2009-11-10 4 views
15

Ich habe ein Problem mit benutzerdefinierten Fehlern auf einer ASP.NET MVC App, die ich auf meinem freigegebenen Host bereitgestellt habe. Ich habe einen ErrorController erstellt und den folgenden Code zu Global.asax hinzugefügt, um nicht behandelte Ausnahmen abzufangen, sie zu protokollieren und dann die Steuerung an den ErrorController zu übergeben, um benutzerdefinierte Fehler anzuzeigen. Dieser Code wird von here genommen:ASP.NET MVC App benutzerdefinierte Fehlerseiten nicht in freigegebenen Hosting-Umgebung angezeigt

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 definitiv feuert, weil die Protokollierung gut funktioniert, sondern meine eigenen Fehlerseiten angezeigt wird, bekomme ich die Go Daddy generischen. Aus dem Titel des Blogposts, aus dem der obige Code stammt, bemerke ich, dass er Release Candidate 2 des MVC-Frameworks verwendet. Hat sich in 1.0 etwas geändert, wodurch die letzte Codezeile nicht funktioniert? Wie immer .

Alle Vorschläge werden sehr geschätzt.

Bearbeiten: Vergessen zu erwähnen, dass ich alle 3 Möglichkeiten für den customErrors-Modus in Web.config ausprobiert habe (Aus, Ein und RemoteOnly). Gleiche Ergebnisse unabhängig von dieser Einstellung.

Edit 2: Und ich habe es auch mit und ohne die [HandleError] Dekoration auf den Controller-Klassen versucht.

Update: Ich habe herausgefunden und repariert die 404s. Es gibt einen Abschnitt des Einstellungsfensters im Hosting-Kontrollzentrum von Go Daddy, in dem das Verhalten von 404 gesteuert werden kann. Standardmäßig wird die generische Seite angezeigt. Dies überschreibt offensichtlich alle Einstellungen von Web.config. Meine benutzerdefinierte 404-Seite wird jetzt wie gewünscht angezeigt. 500s und 503 funktionieren jedoch immer noch nicht. Ich habe Code in dem Homecontroller habe eine statische Textversion des Inhalts zu greifen, wenn SQL Server eine Ausnahme auslöst wie folge:

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); 
     } 
    } 
} 

Hier ist der Code ist, das die statischen Inhalte zu holen versucht:

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; 
} 

Ich habe überprüft, dass, wenn ich die Verbindungszeichenfolge ändere, um eine SqlException zu generieren, der Code den Fehler ordnungsgemäß protokolliert und dann den statischen Inhalt erfasst und anzeigt. Wenn ich aber auch den Pfad zur statischen Textdatei in Web.config ändere, um die 503-Version der Home-Ansicht zu testen, bekomme ich stattdessen eine Seite mit nichts anderem als "Dienst nicht verfügbar". Das ist es. Keine benutzerdefinierte 503-Nachricht mit dem Erscheinungsbild der Website.

Hat jemand irgendwelche Vorschläge zu Verbesserungen am Code, die helfen könnten? Wäre es hilfreich, der HttpResponse verschiedene Header hinzuzufügen? Oder entführt Go Daddy schwerfällig die 503er?

Antwort

29

Ich habe die Lösung gefunden und es ist unglaublich einfach. Stellt sich heraus, dass das Problem tatsächlich in IIS7 war. Während das Debuggen dieses Problem in Visual Studio sah ich eine Eigenschaft des Httpresponse-Objekt, das ich vorher nicht bemerkt hatte:

public bool TrySkipIisCustomErrors { get; set; } 

Diese mich zu meiner nächsten Suchmaschine führen, die auch eine great blog post by Rick Strahl und eine andere auf angrypets.com aufgedreht als this question here on SO. Diese Links erklären die blutigen Details viel besser als ich kann, aber dieses Zitat von Ricks Post fängt es ziemlich gut:

Die wirkliche Verwirrung tritt hier, da der Fehler durch ASP.NET gefangen ist, aber dann letztlich noch behandelt von IIS, die den 500-Statuscode betrachtet und die II-Fehlerseiten-Seite zurückgibt.

Es scheint auch, dass dieses Verhalten spezifisch für IIS7 im integrierten Modus ist. Von msdn:

Wenn im Classic-Modus in IIS 7.0 der TrySkipIisCustomErrors Eigenschaft Standardwert ist true. Bei Ausführung im integrierten Modus ist der Standardwert TrySkipIisCustomErrors false.

So im Wesentlichen alles, was ich zu tun, die am Ende zu ist Response.TrySkipIisCustomErrors = true; hinzufügen direkt nach jedem Code, der die Response.StatusCode-500 oder 503 und alles funktioniert jetzt setzt wie vorgesehen.

+1

+1 Danke, Bryan. Nach über 2 Stunden Suche hast du mir die Antwort gegeben, die ich brauchte. Es ist so einfach. Ich habe versucht, einen 404 Fehlercode zu setzen, der mir eine Sicherheitsausnahme und "Response.TrySkipIisCustomErrors = true;" gab behoben. –

+2

Das hat mich verrückt gemacht. Ich danke dir sehr. Platzieren von "Response.TrySkipIisCustomErrors = true;" Unmittelbar nach dem Setzen der Response-Codes in meinem Error-Controller funktioniert das für mich. Es war irreführend, weil meine lokale IIS 7-Instanz meine benutzerdefinierten Fehleransichten rendert hat, der Remote-Staging-Server jedoch nicht. = P – NovaJoe

+0

Ich war im selben Boot nach der Anwendung, was in dieser Antwort zur Verfügung gestellt wird: http://Stackoverflow.com/a/7499406/114029. 'Response.TrySkipIisCustomErrors = true;' kommt vom Himmel! :) –

0

Ich hosten eine ASP.NET MVC-Site auf GoDaddy und auch Probleme mit benutzerdefinierten Fehlerseiten konfrontiert. Was ich durch Versuch und Irrtum herausgefunden habe, war, dass GoDaddy Fehler auf HTTP-Ebene abfängt.

Zum Beispiel führte jede Seite, die einen HTTP-Statuscode 404 zurückgab, dazu, dass die benutzerdefinierte Fehlerseite von GoDaddy übernommen wurde. Schließlich änderte ich meine benutzerdefinierten Fehlerseiten, um 200 Status zurückzugeben, und das 404-Problem verschwand. Mein HTML war derselbe, nur der HTTP-Status, der geändert werden musste.

Ich habe zwar nie versucht, das gleiche mit 503 Statusantworten zu tun, aber es ist möglich, dass die gleiche Mitigation funktioniert. Wenn Sie vom Zurückgeben eines 503-Status zum Zurückgeben des 200-Status wechseln, verschwindet das Problem?Wenn Sie diese Problemumgehung verwenden, möchten Sie möglicherweise verhindern, dass Suchmaschinen Ihre Fehlerseiten indizieren, die dann, wenn sie einen 200-Status zurückgeben, von der normalen Seite (aus der Perspektive der Suchmaschine) nicht mehr zu unterscheiden sind. Stellen Sie daher sicher, dass Sie ein META ROBOTS-Tag hinzufügen, um die Indexierung Ihrer Fehlerseiten zu verhindern, z.

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

Der Nachteil dieses Ansatzes sein kann, dass Ihre Seite von Google entfernt werden könnte, das ist definitiv nicht eine gute Sache ist!

UPDATE: zusätzlich So können Sie auch erkennen, ob die User-Agent ein Crawler ist oder nicht, und wenn es ein Crawler zurückzukehren, während ein 503 ist, wenn es nicht ein Crawler ist, zurückgeben 200. Siehe this blog post für Infos darüber, wie Crawler erkannt werden. Ja, ich weiß, dass die Rückgabe von verschiedenen Inhalten an Crawler im Vergleich zu Benutzern ein SEO-No-No ist, aber ich habe dies bisher auf mehreren Websites ohne negative Auswirkungen getan, daher bin ich mir nicht sicher, was für ein Problem das ist.

Beide Ansätze (META-ROBOTER und Bot-Erkennung) können die beste Lösung sein, falls Oddball-Crawler durch den Bot-Detektor rutschen.

+0

Danke Justin. Ich fand schließlich heraus, wie man die 404s repariert, sehe mein Update oben. Das Problem mit diesem Ansatz in meiner Situation ist, dass einige der 503 die freundliche Nachricht auf der tatsächlichen Seite anzeigen, wo der Inhalt gewesen wäre. Wenn ich 200 statt 503 zurücksende und Pech habe, dass Crawler an diesem Tag indexieren, indexieren sie meine freundliche Fehlermeldung anstelle des richtigen Inhalts. Das wird in meinem speziellen Fall nicht funktionieren. Danke für die Antwort. – Bryan

+0

Yep, muss auf Crawler aufpassen. Ich habe in meinem ursprünglichen Beitrag darauf hingewiesen, dass Sie ein ROBOTS META-Tag verwenden können, um dies zu umgehen, aber ich habe gerade weitere Details hinzugefügt. Siehe oben. –

+0

Sie haben vielleicht keine negativen Auswirkungen gesehen, aber es gibt keine Möglichkeit zu wissen, dass das gleiche für mich und meinen Kunden gilt :-).Ich zögere, Ihre Vorgehensweise in Betracht zu ziehen, da dies dazu führen könnte, dass mein Kunde und damit auch ich aus den Suchmaschinenindizes entfernt und/oder ausgeschlossen werden. – Bryan

Verwandte Themen