Como fazer com que páginas de erro personalizadas funcionem no ASP.NET MVC 4

Eu quero uma página de erro personalizada mostrada para 500, 404 e 403. Aqui está o que eu fiz:

  1. Ativou erros customizados no web.config da seguinte forma:

        
  2. HandleErrorAttribute registrado como um filtro de ação global na class FilterConfig seguinte forma:

     public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new CustomHandleErrorAttribute()); filters.Add(new AuthorizeAttribute()); } 
  3. Criei uma página de erro personalizada para cada uma das mensagens acima. O padrão para 500 já estava disponível fora da checkbox.

  4. Declarado em cada visualização de página de erro customizada que o modelo para a página é System.Web.Mvc.HandleErrorInfo

Para 500, mostra a página de erro personalizada. Para outros, isso não acontece.

Há algo que estou perdendo?

Parece que isso não é tudo o que há para exibir erros personalizados enquanto eu leio o código no método HandleErrorAttribute class HandleErrorAttribute e ele está manipulando apenas 500.

O que tenho que fazer para lidar com outros erros?

Minha configuração atual (no MVC3, mas acho que ainda se aplica) depende de ter um ErrorController , então eu uso:

      

E o controlador contém o seguinte:

 public class ErrorController : Controller { public ViewResult Index() { return View("Error"); } public ViewResult NotFound() { Response.StatusCode = 404; //you may want to set this to 200 return View("NotFound"); } } 

E as visões do jeito que você as implementa. Eu tendem a adicionar um pouco de lógica, para mostrar o rastreamento de pilha e as informações de erro, se o aplicativo estiver no modo de debugging. Então Error.cshtml é algo como isto:

 @model System.Web.Mvc.HandleErrorInfo @{ Layout = "_Layout.cshtml"; ViewBag.Title = "Error"; } 
Error
An unexpected error has occurred. Please contact the system administrator.
@if (Model != null && HttpContext.Current.IsDebuggingEnabled) {

Exception: @Model.Exception.Message
Controller: @Model.ControllerName
Action: @Model.ActionName

 @Model.Exception.StackTrace 

}

Já fiz solução pablo e sempre tive o erro (MVC4)

A visualização “Erro” ou seu mestre não foi encontrada ou nenhum mecanismo de visualização suporta o local pesquisado.

Para se livrar disso, remova a linha

  filters.Add(new HandleErrorAttribute()); 

em FilterConfig.cs

Eu faço algo que requer menos codificação do que as outras soluções postadas.

Primeiro, no meu web.config, tenho o seguinte:

     

E o controlador (/Controllers/ErrorPageController.cs) contém o seguinte:

 public class ErrorPageController : Controller { public ActionResult Oops(int id) { Response.StatusCode = id; return View(); } } 

E, finalmente, a visão contém o seguinte (despojado para simplificar, mas pode conta:

 @{ ViewBag.Title = "Oops! Error Encountered"; } 

@Response.Status

Possible causes:

  • Baptist explanation: There must be sin in your life. Everyone else opened it fine.
  • Presbyterian explanation: It's not God's will for you to open this link.
  • Word of Faith explanation: You lack the faith to open this link. Your negative words have prevented you from realizing this link's fulfillment.
  • Charismatic explanation: Thou art loosed! Be commanded to OPEN!
  • Unitarian explanation: All links are equal, so if this link doesn't work for you, feel free to experiment with other links that might bring you joy and fulfillment.
  • Buddhist explanation: .........................
  • Episcopalian explanation: Are you saying you have something against homosexuals?
  • Christian Science explanation: There really is no link.
  • Atheist explanation: The only reason you think this link exists is because you needed to invent it.
  • Church counselor's explanation: And what did you feel when the link would not open?


HTTP @Response.StatusCode - @Response.StatusDescription

Eu recomendaria usar o arquivo Global.asax.cs.

  protected void Application_Error(Object sender, EventArgs e) { var exception = Server.GetLastError(); if (exception is HttpUnhandledException) { Server.Transfer("~/Error.aspx"); } if (exception != null) { Server.Transfer("~/Error.aspx"); } try { // This is to stop a problem where we were seeing "gibberish" in the // chrome and firefox browsers HttpApplication app = sender as HttpApplication; app.Response.Filter = null; } catch { } } 

Parece haver vários passos aqui misturados. Vou apresentar o que fiz do zero.

  1. Crie o controlador ErrorPage

     public class ErrorPageController : Controller { public ActionResult Index() { return View(); } public ActionResult Oops(int id) { Response.StatusCode = id; return View(); } } 
  2. Adicione visualizações para essas duas ações (clique com o botão direito -> Adicionar visualização). Estes devem aparecer em uma pasta chamada ErrorPage.

  3. Dentro do App_Start abra FilterConfig.cs e comente o filtro de tratamento de erros.

     public static void RegisterGlobalFilters(GlobalFilterCollection filters) { // Remove this filter because we want to handle errors ourselves via the ErrorPage controller //filters.Add(new HandleErrorAttribute()); } 
  4. Dentro do web.config, adicione as seguintes inputs , em System.Web

         
  5. Teste (claro). Lance uma exceção não tratada em seu código e veja-o ir para a página com o id 500 e, em seguida, use um URL para uma página que não existe para ver 404.

Com base na resposta postada pelo maxspan, eu juntei um projeto de amostra mínimo no GitHub mostrando todas as partes em funcionamento.

Basicamente, apenas adicionamos um método Application_Error a global.asax.cs para interceptar a exceção e nos dar uma oportunidade de redirect (ou, mais corretamente, transferir a solicitação ) para uma página de erro personalizada.

  protected void Application_Error(Object sender, EventArgs e) { // See http://stackoverflow.com/questions/13905164/how-to-make-custom-error-pages-work-in-asp-net-mvc-4 // for additional context on use of this technique var exception = Server.GetLastError(); if (exception != null) { // This would be a good place to log any relevant details about the exception. // Since we are going to pass exception information to our error page via querystring, // it will only be practical to issue a short message. Further detail would have to be logged somewhere. // This will invoke our error page, passing the exception message via querystring parameter // Note that we chose to use Server.TransferRequest, which is only supported in IIS 7 and above. // As an alternative, Response.Redirect could be used instead. // Server.Transfer does not work (see https://support.microsoft.com/en-us/kb/320439 ) Server.TransferRequest("~/Error?Message=" + exception.Message); } } 

Controlador de Erros:

 ///  /// This controller exists to provide the error page ///  public class ErrorController : Controller { ///  /// This action represents the error page ///  /// Error message to be displayed (provided via querystring parameter - a design choice) ///  public ActionResult Index(string Message) { // We choose to use the ViewBag to communicate the error message to the view ViewBag.Message = Message; return View(); } } 

Visualização da página de erro:

 < !DOCTYPE html>   Error   

My Error

@ViewBag.Message

Nada mais está envolvido, além de desabilitar / remover filters.Add(new HandleErrorAttribute()) em FilterConfig.cs

 public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { //filters.Add(new HandleErrorAttribute()); // < == disable/remove } } 

Embora muito simples de implementar, a única desvantagem que vejo nessa abordagem é usar a querystring para fornecer informações de exceção à página de erro de destino.

Aqui está a minha solução. Use [ExportModelStateToTempData] / [ImportModelStateFromTempData] é desconfortável na minha opinião.

~ / Visualizações / Home / Error.cshtml:

 @{ ViewBag.Title = "Error"; Layout = "~/Views/Shared/_Layout.cshtml"; } 

Error


@Html.ValidationMessage("Error")

~ / Controllers / HomeController.sc:

 public class HomeController : BaseController { public ActionResult Index() { return View(); } public ActionResult Error() { return this.View(); } ... } 

~ / Controllers / BaseController.sc:

 public class BaseController : Controller { public BaseController() { } protected override void OnActionExecuted(ActionExecutedContext filterContext) { if (filterContext.Result is ViewResult) { if (filterContext.Controller.TempData.ContainsKey("Error")) { var modelState = filterContext.Controller.TempData["Error"] as ModelState; filterContext.Controller.ViewData.ModelState.Merge(new ModelStateDictionary() { new KeyValuePair("Error", modelState) }); filterContext.Controller.TempData.Remove("Error"); } } if ((filterContext.Result is RedirectResult) || (filterContext.Result is RedirectToRouteResult)) { if (filterContext.Controller.ViewData.ModelState.ContainsKey("Error")) { filterContext.Controller.TempData["Error"] = filterContext.Controller.ViewData.ModelState["Error"]; } } base.OnActionExecuted(filterContext); } } 

~ / Controllers / MyController.sc:

 public class MyController : BaseController { public ActionResult Index() { return View(); } public ActionResult Details(int id) { if (id != 5) { ModelState.AddModelError("Error", "Specified row does not exist."); return RedirectToAction("Error", "Home"); } else { return View("Specified row exists."); } } } 

Desejo-lhe projetos de sucesso 😉

Você pode obter erros trabalhando corretamente sem hackear global.cs, mexendo com HandleErrorAttribute, fazendo Response.TrySkipIisCustomErrors, conectando Application_Error, ou o que quer que seja:

Em system.web (apenas o usual, on / off)

     

e no system.webServer

  

Agora as coisas devem se comportar como esperado, e você pode usar seu ErrorController para mostrar o que você precisa.

Eu tinha tudo configurado, mas ainda não conseguia ver páginas de erro adequadas para o código de status 500 em nosso servidor de teste, apesar de tudo ter funcionado bem em servidores de desenvolvimento local.

Eu encontrei este post do blog de Rick Strahl que me ajudou.

Eu precisava adicionar Response.TrySkipIisCustomErrors = true; ao meu código de manipulação de erro personalizado.

Parece que cheguei atrasado para a festa, mas é melhor você checar isso também.

Então, em system.web para o cache de exceções dentro do aplicativo, como retornar HttpNotFound ()

        

e no system.webServer para recuperar erros que foram capturados pelo IIS e não foram para a estrutura do asp.net

         

No último caso você se preocupe com a resposta do cliente, altere o responseMode="Redirect" para responseMode="File" e forneça um arquivo html estático, já que este exibirá uma página amigável com um código de 200 respostas.

No web.config, adicione isto na tag system.webserver como abaixo,

        

e adicione um controlador como,

 public class ErrorController : Controller { // // GET: /Error/ [GET("/Error/NotFound")] public ActionResult NotFound() { Response.StatusCode = 404; return View(); } [GET("/Error/ErrorPage")] public ActionResult ErrorPage() { Response.StatusCode = 500; return View(); } } 

e adicionar seus pontos de vista respeitados, isso vai funcionar definitivamente eu acho que para todos.

Esta solução eu encontrei de: Neptune Century