tutorial pages net mvc asp c# asp.net-mvc asp.net-mvc-4 asp.net-mvc-5 unhandled-exception

c# - net - razor pages or mvc



En ASP.NET MVC, ¿cuál es el mejor espectáculo de excepciones no controladas en mi opinión? (3)

Hago algo similar a maxlego, que maneja todos los errores (no solo los que ocurren en los controladores con el atributo HandleError).

Mi clase MvcApplication (en global.asax.cs) tiene esto:

public class MvcApplication : HttpApplication { // usual stuff here... protected void Application_Error(object sender, EventArgs e) { Server.HandleError(((MvcApplication)sender).Context); } }

El código anterior usa un método de extensión de mi biblioteca MVC de cosas útiles. Con esto en su lugar, no necesito ningún error al manejar los atributos, customErrors config o filtros personalizados. En cambio, el método de extensión registrará los detalles del error e invocará una vista adecuada, ya sea:

  • Acceso denegado
  • Extraviado
  • Error de servidor interno

El código del método de extensión para hacer que esto funcione es:

public static class HttpServerUtilityExtensions { private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); public static void HandleError(this HttpServerUtility server, HttpContext httpContext) { var currentController = " "; var currentAction = " "; var currentRouteData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(httpContext)); if (currentRouteData != null) { if (currentRouteData.Values["controller"] != null && !String.IsNullOrEmpty(currentRouteData.Values["controller"].ToString())) currentController = currentRouteData.Values["controller"].ToString(); if (currentRouteData.Values["action"] != null && !String.IsNullOrEmpty(currentRouteData.Values["action"].ToString())) currentAction = currentRouteData.Values["action"].ToString(); } var exception = server.GetLastError(); Logger.ErrorException(exception.Message, exception); var controller = DependencyResolver.Current.GetService<ErrorController>(); var routeData = new RouteData(); var action = "InternalServerError"; if (exception is HttpException) { var httpEx = exception as HttpException; switch (httpEx.GetHttpCode()) { case 404: action = "NotFound"; break; case 401: action = "AccessDenied"; break; } } httpContext.ClearError(); httpContext.Response.Clear(); httpContext.Response.StatusCode = exception is HttpException ? ((HttpException)exception).GetHttpCode() : 500; httpContext.Response.TrySkipIisCustomErrors = true; routeData.Values["controller"] = "Error"; routeData.Values["action"] = action; controller.ViewData.Model = new HandleErrorInfo(exception, currentController, currentAction); ((IController)controller).Execute(new RequestContext(new HttpContextWrapper(httpContext), routeData)); } }

Tenga en cuenta que lo anterior utiliza NLog para registrar los detalles del error, pero podría cambiarse fácilmente para admitir algo más. Además, este método respeta su contenedor IoC al resolver el ErrorController.

Tengo lo siguiente en mi web.config:

<customErrors mode="On" defaultRedirect="Error"> <error statusCode="404" redirect="Error/NotFound" /> </customErrors>

tengo un

[HandleError]

en la parte superior de mi clase HomeController. Para probar, creo y acción que simplemente arroja una excepción. . y redirige a mi

ErrorController/Index

método, pero cuando llega a mi punto de vista que se une a HandleErrorInfo mi modelo es nulo, así que de alguna manera he perdido la referencia al error.

Estoy seguro de que tiene algo que ver con el error que se perdió en la redirección, así que quería ver si me faltaba algo y si alguien tenía sugerencias en las que puedo tener una vista que muestra el mensaje StackTrace y el mensaje de error.


He usado este pequeño fragmento de código para mostrar a los usuarios la página de errores manejados. Si la página no se encontró o se produjo algún otro error.

void Application_Error(object sender, EventArgs e) { // this value can be fetched from config or depend on DEBUG smybol if (!handleErrors) return; var error = Server.GetLastError(); var code = (error is HttpException) ? (error as HttpException).GetHttpCode() : 500; if (code == 404) { // do something if page was not found. log for instance } else { // collect request info and log exception } // pass exception to ErrorsController Request.RequestContext.RouteData.Values["ex"] = error; // execute controller action IController errorController = new ErrorsController(); errorController.Execute(new RequestContext(new HttpContextWrapper(Context), Request.RequestContext.RouteData)); }

Y el controlador de errores se ve algo así. Si necesita una excepción detallada, se puede acceder a través de RouteData

public class ErrorsController : Controller { /// <summary> /// Page not found /// </summary> /// <returns></returns> public ActionResult Http404() { return View(); } /// <summary> /// All other errors /// </summary> /// <param name="actionName"></param> protected override void HandleUnknownAction(string actionName) { // in case detailed exception is required. var ex = (Exception) RouteData.Values["ex"]; return View(); } }

Puede agregar diferentes vistas para cada código http. Solo implemente la acción Http {Code}


Puedo ver el concepto erróneo. Desea hacer lo de MVC y redirect a una acción de controlador.

Pero defaultRedirect es en sí mismo una convención de Web Form y por lo tanto limitada. En el momento en que redirige a otro controlador, perderá su HttpContext , y perderá así su objeto HandleErrorInfo

Su [HandleError] requiere una View para dirigir su mensaje de error a. Siguiendo su ejemplo anterior, supongo que tiene una carpeta Views/Error para su ErrorController , y en ella tiene una vista de Index . Si desea que su contexto de filtro envíe un objeto HandleErrorInfo a esa vista,

Prueba esta sintaxis:

[HandleError(View="~/Views/Error/Index")] Public class HomeController : Controller

Pero ¿qué hay de la tala?!?!?

Sospecho que su intención es más que simplemente mostrar la pila de errores a los usuarios. De hecho, sospecho que no tienes esa intención en absoluto. Sospecho que tu objetivo real es registrar tu error (probablemente en db) y mostrar un mensaje insípido a tu usuario.

Lo que he explicado hasta ahora fue " lo que es mejor [forma de] mostrar excepciones no manejadas en mi opinión ". El atributo [HandleError] es bueno para eso.

Pero cuando desee pasar al siguiente paso (registrar el error), tiene algunas opciones:

1) Anula el método On Exception de tu controlador base ; cree su propio Controller hereda de la clase MVC Controller pero anule el método On Exception. Este enfoque se puede usar junto con el atributo [HandleError]

2) Cree un controlador personalizado de excepciones Cree su propio controlador de excepciones que registre el error. Su manejador de excepciones puede llamar a una Vista de elección o puede trabajar en conjunto con [HandleError(order=2)] ya que los atributos de filtro pueden tomar un argumento de orden aplicando precedencia.

Nitin Sawant pregunta cómo sería una vista de error. los

@model System.Web.Mvc.HandleErrorInfo <h2>Exception details</h2> <p> Controller: @Model.ControllerName </p> <p> Action: @Model.ActionName </p> <p> Exception: @Model.Exception </p>