longchamp
tory burch outlet
tory burch outlet
ray ban australia
Babyliss
nike air max
Michael Kors outlet
toms outlet
nike air max
louis vuitton outlet
nike air max
coach outlet
nike air max
ray ban uk
oakley sunglasses
Michael Kors outlet
Global HandleErrorAttribute in ASP.net MVC3

Global HandleErrorAttribute in ASP.net MVC3

On November 29, 2011, in ASP.net, MVC3, by jonathancreamer

My boss once told me, “Good programming is good Error Handling”. No user enjoys the infamous YSOD(Yellow Screen of Death). It’s just ugly, and shows a general lack of concern over your code if it occurs in a production environment!

However, let’s face it…Bug’s happen. Sometimes there’s nothing you can do about it, others you can. Either way, the End-User should never see the YSOD.

Fortunately in MVC3, there is a built in piece of functionality that comes standard when you create a new MVC project.

It’s called the HandleErrorAttribute, and it can be applied in two different ways. First off is the method by method or class by class way of doing it.

// Use it here
[HandleError]
public class HomeController : Controller
{
    // Or here
    // [HandleError] 
    public ActionResult Index()
    {
        return View();
    }
}

The other way is by utilizing the Global Filters of MVC3. This comes default in a new MVC3 project, and is located in the Global.asax file.

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    filters.Add(new HandleErrorAttribute());
}

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
    );

}

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);
}

The part of this to note is the filters.Add(new HandleErrorAttribute()); This turns on error handling for every controller in your app.

Please Note: It will only handle 500 errors, so 404’s need to be handled differently. I’ll get to that shortly.

The next step in the process is to turn on customErrors in the web.config file at the root of the web app, (NOT the one in the /views folder).

Find <system.web> in your web.config, and then put this in there…


<customerrors mode="On" defaultredirect="~/Error/HttpError">
    <error redirect="~/Error/NotFound" statuscode="404" />
</customerrors>

The defaultredirect allows you to have somewhere to go in case your error page errors, and the error allows you to have different places to go depending on the error code. You can handle 404 errors that way…

The last thing you’ll need for the defaultredirect is a simple ErrorController.

public class ErrorController : BaseController
{
    //
    // GET: /Error/
    public ActionResult HttpError()
    {
       return View("Error");
    }
     public ActionResult NotFound()
    {
        return View();
    }
    public ActionResult Index()
    {
        return RedirectToAction("Index", "Home");
    }
}

The default error view comes in the /views/shared/Error.cshtml folder. This is where MVC will look to find the view to render and display the error message.

@model System.Web.Mvc.HandleErrorInfo
@{
    ViewBag.Title = "General Site Error";
}

<h2>A General Error Has Occurred</h2>

@if (Model != null)
{
    <p>@Model.Exception.GetType().Name<br />
    thrown in @Model.ControllerName @Model.ActionName</p>
    <p>Error Details:</p>
    <p>@Model.Exception.Message</p>
}

You can overwrite this by passing a view argument to the GlobalFilter, as well as specifying a specifc type of exception, and an order in which to handle the error if you choose to have multiple HandleErrors.

filters.Add(new HandleErrorAttribute
{
    ExceptionType = typeof(YourExceptionHere),
    // DbError.cshtml is a view in the Shared folder.
    View = "DbError",
    Order = 2
});
  • Pingback: The Morning Brew - Chris Alcock » The Morning Brew #992

  • http://www.Marisic.Net dotnetchris

    FWIW you’re still technically handling 4xx errors wrong. Those should not redirect to a page, they should return directly with their response status code of 4xx with no redirect.

    I don’t know why ASP.NET made it so much work to properly respond to errors =/

    • http://dan.cx/ Daniel Lo Nigro

      Since .NET Framework 3.5 SP1, you can put redirectMode=”ResponseRewrite” on the customErrors web.config node to force it to do a rewrite instead of a redirect.

      • http://www.Marisic.Net dotnetchris

        It’s far from that simple when 4xx should be direct responses, 500 should be 302 then 500, and then you couple this to the nonsense of IIS custom errors that try to intercept your direct response output.

        I’ve spent probably 50 hours of my career, if not 100, 150 hours purely on custom errors handling on apps. And i still don’t have everything perfect.

        • http://dan.cx/ Daniel Lo Nigro

          Why should 500 errors be a 302 then a 500? Other than ASP.NET, I’ve never seen *any* system that does a redirect when an error occurs. Look at any non-ASP.NET site and you’d probably find that it doesn’t redirect when an error occurs.

          • http://www.Marisic.Net dotnetchris

            Because /url 500 = that url is dead and search engines will delist it. Whereas /url redirect 500, will last through many more spider hits before it decides to delist /url and instead index where it redirects to.

          • http://dan.cx/ Daniel Lo Nigro

            Do you have any proof that search engines delist URLs that return 500 errors? Not all 500 errors are permanent and I’ve never seen a search engine delist sites that return 500 errors temporarily.

  • Anonymous

    @dotnetchris Yea, it’s quite a pain. Are you saying that the redirect in the web.config is wrong, or the redirect in the ErrorController is wrong? I ask because the redirect in the ErrorController is only there to prevent the users from accessing /Error/Index

  • Sam Stephens

    The redirect in the web config is wrong. When a page has an error, the response shouldn’t be a redirect to another page. The response should be a page returned with a 500 response code (or 404 for not found). This is something that ASP.NET has done wrong from the start.

    • http://www.Marisic.Net dotnetchris

      Actually that is last part is incorrect Sam. In a regular application (aka not a RESTful web service), the proper way to handle a 500 error is to issue a 302 temporary redirect, then redirect to the 500 error page that returns a proper 500 status code.

      For a server to issue a 500 error directly without redirect can cause your server to be deindexed from search engines as it appears to be a globally bad server. It responds to a regular request with a 500. When it responds with a 302, then a 500, search indexes see that currently something is wrong with X url, but later it should be available. Responding directly with a 500 is saying this url will NEVER work. This last statement is why it’s appropriate to respond with 4XX errors immediately. These requests are permanent failures, and will never resolve properly no matter how many times you reply them (against the same server configuration atleast). when they’re properly issued.

      • stevejay

        @dotnetchris As you say, 4xx errors should be handled without a redirect. But regarding 500 errors, I find it hard to believe that handling these by _not_ redirecting can cause the server to be deindexed from search engines, at least not unless the error remains unfixed for a very long time. The definition for a 500 error in the HTTP 1.1 spec is simply, “The server encountered an unexpected condition which prevented it from fulfilling the request.” There is no mention of permanency of the condition.

        • http://www.Marisic.Net dotnetchris

          Never was probably a bit overzealous to use there. Without responding with a 302 first however will tell the client the SERVER is dead, as opposed to the server is fine but the page itself is encountering an error.

          And yes search engine internals are voodoo, so who knows how many times a url needs crawled returning a 500 to get deindexed. Even if ASP.NET does error handling somewhat poor out of box without alot of effort, it atleast errs substantially on the side of caution by doing a redirect for everything first.

          • stevejay

            @dotnetchris You wrote “Without responding with a 302 first however will tell the client the SERVER is dead”. Again, the definition for a 500 error in the HTTP 1.1 spec is simply, “The server encountered an unexpected condition which prevented it from fulfilling the request.” Returning a 500 response for the requested page does absolutely not tell the client that the server is dead. All that is known is that the server was unable, for some reason, to serve the requested page.

            You wrote “When it responds with a 302, then a 500, search indexes see that currently something is wrong with X url, but later it should be available.”. Since I’ve said that a 500 error does not indicate the permanence of the error, responding with just a 500 error does not tell the search engines that the X url should not be available later.

    • http://dan.cx/ Daniel Lo Nigro

      If you don’t want it to redirect, just set redirectMode=”ResponseRewrite”

  • Troy Alford

    Great post – very helpful insight into some of the plumbing of ActionFilterAttributes.

    Curious if you’ve had any opportunity to update your solution given dotnetchris’ feedback RE: sending 302′s and 500′s? I’d love to see a good full-featured implementation for correctly handling status codes and such. :)

  • T54y

    hh

    • Frg

      ty5y

  • Rajesh

    i like it

  • Bargoder

    its very easy

  • Kevin Logan

    Great article! Thanks for making it straightforward and all in one place.