2009-11-10 25 views
15

Tengo un problema con los errores personalizados en una aplicación ASP.NET MVC que he implementado en mi host compartido. Creé un ErrorController y agregué el siguiente código a Global.asax para capturar las excepciones no controladas, registrarlas y luego transferir el control al ErrorController para mostrar los errores personalizados. Este código se toma de here:Las páginas de error personalizadas de la aplicación ASP.NET MVC no se muestran en el entorno de alojamiento compartido

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 es, sin duda disparando debido a que el registro funciona bien, pero en lugar de mostrar mis páginas de error personalizadas, consigo los genéricos Go Daddy. Del título de la publicación del blog del que se tomó el código anterior, observo que usa Release Candidate 2 del framework MVC. ¿Algo cambió en 1.0 que hace que la última línea de código no funcione? Como de costumbre, es works great on my machine.

Cualquier sugerencia será muy apreciada.

Editar: Olvidé mencionar que probé las 3 posibilidades para el modo CustomErrors en Web.config (Off, On y RemoteOnly). Los mismos resultados independientemente de esta configuración.

Edit 2: Y también lo he probado con y sin la decoración [HandleError] en las clases de Controller.

Actualización: He descubierto y solucionado los 404. Hay una sección del panel de Configuración en el Centro de Control de Alojamiento de Go Daddy donde se puede controlar el comportamiento de 404 y el predeterminado es mostrar su página genérica, y aparentemente esto anula cualquier configuración de Web.config. Así que mi página 404 personalizada ahora se muestra como estaba previsto. Sin embargo, 500s y 503s todavía no están funcionando. Tengo código en el HomeController para agarrar una versión de texto estático del contenido de Si SQL Server genera una excepción de la siguiente manera:

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

Aquí está el código que intenta buscar el contenido estático:

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

He verificado que si cambio la cadena de conexión para generar una SqlException, el código registra correctamente el error y luego toma y muestra el contenido estático. Pero si también cambio la ruta al archivo de texto estático en Web.config para probar la versión 503 de la Vista de inicio, lo que obtengo es una página con nada más que "servicio no disponible". Eso es. No hay un mensaje 503 personalizado con la apariencia del sitio.

¿Alguien tiene alguna sugerencia sobre mejoras en el código que pueda ayudar? ¿Ayudaría agregar diferentes encabezados a HttpResponse? ¿O es que Go Daddy está secuestrando fuertemente a los 503?

Respuesta

29

He encontrado la solución y es increíblemente simple. Resulta que el problema estaba realmente en IIS7. Al depurar este problema en Visual Studio vi una propiedad del objeto HttpResponse que no había notado antes:

public bool TrySkipIisCustomErrors { get; set; } 

Esto me lleva a mi motor de búsqueda más cercana que resultó un great blog post by Rick Strahl y otro en angrypets.com, así como this question here on SO. Estos enlaces se explican los detalles morbosos mucho mejor que pueda, pero esta cita de post de Rick capta bastante bien:

La confusión real aquí se debe a que el error es atrapado por ASP.NET, pero en última instancia, todavía maneja por IIS que mira el código de estado 500 y devuelve la página de error stock IIS.

También parece que este comportamiento es específico de IIS7 en modo integrado. De msdn:

cuando se ejecuta en el modo clásico en IIS 7.0 el valor predeterminado propiedad TrySkipIisCustomErrors es cierto. Cuando se ejecuta en modo integrado, el valor predeterminado de la propiedad TrySkipIisCustomErrors es falso.

Así que, esencialmente todo lo que llegó a tener que hacer es añadir Response.TrySkipIisCustomErrors = true; justo después de cualquier código que establece la Response.StatusCode a 500 o 503 y todo lo que ahora funciona como se ha diseñado.

+1

+1 Gracias, Bryan. Después de más de 2 horas de búsqueda, me diste la respuesta que necesitaba. Es tan simple. Estaba intentando establecer un código de error 404 que me daba una excepción de seguridad y "Response.TrySkipIisCustomErrors = true;" arreglado. –

+2

Esto me estaba volviendo loco. Muchas gracias. Colocando "Response.TrySkipIisCustomErrors = true;" Inmediatamente después de configurar los códigos de respuesta en mi controlador de error, fue lo que funcionó para mí. Fue engañoso porque mi instancia local de IIS 7 estaba representando mis vistas de error personalizadas, pero el servidor de almacenamiento remoto no. = P – NovaJoe

+0

Estaba en el mismo barco después de aplicar lo que se proporciona en esta respuesta: http://stackoverflow.com/a/7499406/114029. 'Response.TrySkipIisCustomErrors = true;' viene del cielo! :) –

0

Alojo un sitio ASP.NET MVC en GoDaddy y también tuve problemas con las páginas de error personalizadas. Lo que encontré, a través de prueba y error, fue que GoDaddy intercepta errores en el nivel HTTP.

Por ejemplo, cualquier página que devuelva un código de estado HTTP de 404 causó que la página de error personalizada de GoDaddy se hiciera cargo. Eventualmente cambié mis páginas de error personalizadas para devolver el estado 200 y el problema relacionado con 404 desapareció. Mi HTML era el mismo, solo el estado HTTP necesario para cambiar.

Reconocidamente, nunca intenté hacer lo mismo con las respuestas de estado 503, pero es posible que la misma mitigación funcione. Si cambia de devolver un estado 503 a regresar al estado 200, ¿el problema desaparece?

Tenga en cuenta que, si realiza esta solución, querrá evitar que los motores de búsqueda indexen sus páginas de error, que una vez que devuelven el estado 200 no se distinguirán (desde la perspectiva del motor de búsqueda) de una página normal. Por lo tanto, asegúrese de agregar una etiqueta META ROBOTS para evitar la indexación de sus páginas de error, p.

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

La desventaja de este enfoque puede ser que su página podría ser eliminado de Google, lo que definitivamente no es una buena cosa!

ACTUALIZACIÓN: Así que, además, también puede detectar si el agente de usuario es un rastreador o no, y si es un rastreador devuelven un 503, mientras que si no es un rastreador, devolver un 200. Véase this blog post para obtener información acerca de cómo detectar rastreadores. Sí, sé que devolver contenido diferente a los rastreadores frente a los usuarios es un SEO no-no, pero lo he hecho en varios sitios sin ningún efecto negativo hasta el momento, por lo que no estoy seguro de cuán problemático es eso.

Hacer ambas aproximaciones (META ROBOTS y detección de bots) puede ser su mejor opción, en caso de que cualquier rastreador oddball se deslice a través del detector de bot.

+0

Gracias Justin. Finalmente descubrí cómo arreglar los 404, consulte mi actualización más arriba. El problema con este enfoque en mi situación es que algunos de los 503 deben mostrar el mensaje amistoso en la página real donde habría estado el contenido. Si devuelvo un 200 en lugar de 503 y tengo la mala suerte de indexar esos rastreadores ese día, indexarán mi mensaje de error amistoso en lugar del correcto. Entonces esto no funcionará en mi caso particular. Gracias por la respuesta. – Bryan

+0

sí, tengo que tener cuidado con los rastreadores. Noté en mi publicación original que puedes usar una etiqueta ROBOTS META para evitar esto, pero también agregué más detalles. Véase más arriba. –

+0

Es posible que no haya visto ningún efecto negativo, pero no hay manera de saber que lo mismo sería válido para mí y mi cliente :-).Dudo en considerar su enfoque, ya que podría provocar que mi cliente, y por extensión yo, sea eliminado y/o excluido de los índices de los motores de búsqueda. – Bryan

Cuestiones relacionadas