Tengo un atributo personalizado HandleError
que se ocupa de los errores en la canalización de MVC; Tengo un método protected void Application_Error(object sender, EventArgs e)
en mi Global.asax
que maneja los errores desde fuera de la tubería.ASP.NET MVC Global error handling
Me he encontrado con un escenario que no sabía que era posible; Al implementar DI, existe una dependencia para connectionString
, que se toma del archivo de configuración de la aplicación.
Como no existía la cadena de conexión, sin embargo, plantea un error al crear el controlador, esto por lo general hace que el fuego Application_Error
manipulador, y una página de error adecuado se vuelve (a través de la prestación de una vista parcial como cadena y enviándolo como el "excepción grave".. la respuesta, y en caso de que esto no sólo se escribe en la respuesta
Salvo en este caso, me sale el ASP.NET "error de ejecución" fugly por defecto pantalla amarilla de la muerte me dice:
Runtime Error
Descripción: Se ha producido un error de aplicación en el servidor . La configuración de error personalizado actual para esta aplicación evita que se vean los detalles del error de la aplicación.
Detalles: Para habilitar los detalles de este mensaje de error específico para ser visible en la máquina servidor local, por favor crear una etiqueta dentro de un archivo de configuración "web.config" ubicado en el directorio raíz de la aplicación web actual . Esta etiqueta debe tener su atributo "modo" establecido en "RemoteOnly". Para habilitar los detalles para que se puedan ver en máquinas remotas, configure "modo" en "Desactivado".
que no tienen un conjunto defaultRedirect
en mi customErrors
, ni es Off
volvió, porque no quiero volver a dirigir, sino para hacer que los errores en la misma página que el usuario se encuentra, evitando una redirección innecesaria.
¿Cómo puedo manejar un escenario como este? ¿Y cuál es la razón por la que se comporta de esta manera y no como cualquier otro error fuera de un controlador?
Me doy cuenta de que no es probable que suceda a menudo, pero me gustaría poder detener el YSOD (en parte porque quiero ocultar la tecnología que estoy usando, pero sobre todo porque no es bonita ni amigable)
Incluso intenté registrar un controlador para UnhandledExceptions, pero tampoco se activó.
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
El código que en última instancia produce esto, es:
return ConfigurationManager.ConnectionStrings[key].ConnectionString;
, donde ConnectionStrings[key]
es null
.
actualización
Esto es cómo se manejan los errores applicaion:
protected void Application_Error(object sender, EventArgs e)
{
this.HandleApplicationError(new ResourceController());
}
public static void HandleApplicationError(this HttpApplication application, BaseController controller)
{
if (application == null)
{
throw new ArgumentNullException("application");
}
if (controller == null)
{
throw new ArgumentNullException("controller");
}
application.Response.Clear();
Exception exception = application.Server.GetLastError();
LogApplicationException(application.Response, exception);
try
{
RenderExceptionViewResponse(application, exception, controller);
}
catch (Exception exceptionRenderingView) // now we're in trouble. let's be as graceful as possible.
{
RenderExceptionTextResponse(application, exceptionRenderingView);
}
finally
{
application.Server.ClearError();
}
}
private static void LogApplicationException(HttpResponse response, Exception exception)
{
if (exception is HttpException)
{
HttpException httpException = (HttpException)exception;
if (httpException.GetHttpCode() == (int)HttpStatusCode.NotFound)
{
_log.Debug(Resources.Error.WebResourceNotFound, httpException);
response.Status = Resources.Constants.NotFound;
return;
}
}
_log.Error(Resources.Error.UnhandledException, exception);
}
private static void RenderExceptionViewResponse(HttpApplication application, Exception exception, BaseController controller)
{
if (!RenderAsJsonResponse(application, Resources.User.UnhandledExceptionJson))
{
ErrorViewModel model = WebUtility.GetErrorViewModel(exception);
string result = controller.RenderViewToString(Resources.Constants.ErrorViewName, model);
application.Response.Write(result);
}
}
private static void RenderExceptionTextResponse(HttpApplication application, Exception exceptionRenderingView)
{
application.Response.Clear();
if (!RenderAsJsonResponse(application, Resources.User.FatalExceptionJson))
{
application.Response.Write(Resources.User.FatalException);
}
_log.Fatal(Resources.Error.FatalException, exceptionRenderingView);
}
private static bool RenderAsJsonResponse(HttpApplication application, string message)
{
if (application.Request.IsAjaxRequest())
{
application.Response.Status = Resources.Constants.HttpSuccess;
application.Response.ContentType = Resources.Constants.JsonContentType;
application.Response.Write(message);
return true;
}
return false;
}
Este es el atributo que utilizo para decorar mi base:
public class ErrorHandlingAttribute : HandleErrorAttribute
{
public Type LoggerType { get; set; }
public ErrorHandlingAttribute()
: this(typeof(ErrorHandlingAttribute))
{
}
public ErrorHandlingAttribute(Type loggerType)
{
LoggerType = loggerType;
}
public override void OnException(ExceptionContext filterContext)
{
if (filterContext.ExceptionHandled)
{
return;
}
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
OnAjaxException(filterContext);
}
else
{
OnRegularException(filterContext);
}
}
internal protected void OnRegularException(ExceptionContext filterContext)
{
Exception exception = filterContext.Exception;
ILog logger = LogManager.GetLogger(LoggerType);
logger.Error(Resources.Error.UnhandledException, exception);
filterContext.HttpContext.Response.Clear();
ErrorViewModel model = WebUtility.GetErrorViewModel(exception);
filterContext.Result = new ViewResult
{
ViewName = Resources.Constants.ErrorViewName,
ViewData = new ViewDataDictionary(model)
};
filterContext.ExceptionHandled = true;
}
internal protected void OnAjaxException(ExceptionContext filterContext)
{
Exception exception = filterContext.Exception;
ILog logger = LogManager.GetLogger(LoggerType);
logger.Error(Resources.Error.UnhandledAjaxException, exception);
filterContext.HttpContext.Response.Clear();
filterContext.HttpContext.Response.Status = Resources.Constants.HttpSuccess;
string errorMessage = WebUtility.GetUserExceptionMessage(exception, true);
filterContext.Result = new ExceptionJsonResult(new[] { errorMessage });
filterContext.ExceptionHandled = true;
}
}
Y esta es mi customErrors
:
<customErrors mode="On" />
Como puede ver, estos son bastante extensos, sin embargo, ni siquiera se disparan en el caso de acceder al ConnectionStrings
donde el ConnectionString
no existe; que es un poco desconcertante.
hace incendio en cualquier controlador contenía excepciones o excepciones que no están dentro de un controlador, por lo que no entiendo por qué este caso es diferente.
He actualizado con mi configuración de manejo de errores. – bevacqua
¿Qué hay de usar PartialView? ¿Podría echar un vistazo a [Manejo de errores globales con PartialView en MVC] (http://stackoverflow.com/questions/39594409/global-error-handling-using-partialview-in-mvc)? –