{"id":1792,"date":"2014-04-10T00:00:00","date_gmt":"2014-04-10T00:00:00","guid":{"rendered":"https:\/\/test.simple-talk.com\/uncategorized\/handling-errors-effectively-in-asp-net-mvc\/"},"modified":"2021-05-17T18:34:53","modified_gmt":"2021-05-17T18:34:53","slug":"handling-errors-effectively-in-asp-net-mvc","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/development\/dotnet-development\/handling-errors-effectively-in-asp-net-mvc\/","title":{"rendered":"Handling Errors Effectively in ASP.NET MVC"},"content":{"rendered":"<div id=\"pretty\">\n<p class=\"start\">Years ago, &#160;ASP.NET&#8217;s error handling was  one of the major things that made me wonder if ASP.NET MVC could give me something that ASP.NET Web Forms couldn&#8217;t. Web  Forms is based on pages; so if something goes wrong, all that you can do is to redirect the user to another page and  explain what the error was or just be generically sorry. ASP.NET Web Forms allow you to map an error page for each  possible HTTP status code. You control the mapping through the <b>&lt;customErrors&gt; <\/b> section of the <b>web.config<\/b> file.<\/p>\n<p class=\"MsoNormal\">Because of the&#160; different  architecture of the view in ASP.NET MVC, &#160;it &#160;is  possible to save the redirect command and then programmatically switch to an error view in the context of the same  request. You have this in addition to the regular page-based error handling mechanism. I wouldn&#8217;t use HTTP code  redirects in ASP.NET MVC; but only because more flexible solutions are possible.<\/p>\n<p class=\"MsoNormal\">Generally speaking, error handling in ASP.NET MVC is mainly necessary to handle  program and route exceptions. Program exceptions refer to catching errors in controllers and in any code you may have in  Razor views. Route exceptions refer to missing links and invalid URLs. <\/p>\n<h1>Program Exceptions<\/h1>\n<p class=\"MsoNormal\">Any stack trace you can have out of an ASP.NET MVC application originates from a  method call in a controller class. The controller class, therefore, is where any exceptions in your ASP.NET MVC code can  be trapped. You can do that in a number of equivalent ways. For example, you can have a try\/catch block surrounding the  entire method body. It works, but it&#8217;s ugly to see too. A better option is probably to override the <b>OnException <\/b>method from the base Controller class. Yet another option is  using the <b>HandleError <\/b>attribute at the controller class level. Better yet, the <b> HandleError <\/b>attribute-which is ultimately an action filter-can be set globally on just every controllers and actions  you can have.<\/p>\n<p class=\"MsoNormal\">At the end of the day, an effective strategy for error handling is based on the  following pillars:<\/p>\n<ul>\n<li>All classes down the controller level just throw exceptions when something goes wrong.<\/li>\n<li>Some of these classes, in some of their methods, may attempt to catch some of the exceptions but mostly when  \t\ta given exception is intended to be swallowed or turned into some other exception. <\/li>\n<li>At the application level you use the HandleError global filter to catch whatever bubbles up.<\/li>\n<\/ul>\n<p class=\"MsoNormal\">Swallowing exceptions is in general a dangerous practice; but in the end it is  not more dangerous than crossing the street when it&#8217;s red but there are no cars in sight. It works well as long as it  doesn&#8217;t become a common practice and as long as it&#8217;s applied with a grain, or maybe two, of salt. Swallowing an  exception is fine for example if your code is trying to call an external HTTP endpoint and the call times out or fails  for whatever reason. In this case it might be acceptable that the routine that takes care of the call just hides the  actual HTTP status code and packs the event as a special case of the regular response. Here&#8217;s an example taken from a  data access repository class:<\/p>\n<pre>public Order FindByCustomerAndId(int id, string customerId)\n{\n&#160;&#160;&#160; using (var db = new MyAppEntities())\n&#160;&#160; &#160;{\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; try\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; var order = (from o in db.Orders \n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; where o.OrderId == id &amp;&amp; o.Buyer.CustomerId == customerId\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; select o).Single();\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; return order;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; }\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; catch (InvalidOperationException)\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; return new NullOrder();\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; }\n&#160;&#160;&#160; }\n}<\/pre>\n<p class=\"MsoNormal\">In LINQ, the Single method just throws an exception if the response includes any  number of items different from one. The internal try\/catch block swallows the exception and returns a special version of  the Order type that just evaluates to NULL.<\/p>\n<p class=\"MsoNormal\">The NullOrder class is an instance of the <a href=\"http:\/\/martinfowler.com\/eaaCatalog\/specialCase.html\">Special Case<\/a> pattern and has the merit of not killing  polymorphism in code as NULL would do. The caller of the aforementioned method will have then the following skeleton:<\/p>\n<pre>var order = _orderRepository.FindByCustomerAndId(orderId, customerId);\nif (order is NullOrder) \n{\n&#160; ...\n}<\/pre>\n<p class=\"MsoNormal\">There are a few guidelines you might want to adhere to when it comes to handling  exceptions. The first aspect to consider is that the <i>catch<\/i> block is quite  expensive and raises a peak of CPU usage when your code gets into it. For this reason, over-catching may end up  affecting the overall performance of the application. It&#8217;s probably not a big deal if your code is frontend; but for  server-side code scaling up the performance of the entire system it might become problematic. <\/p>\n<p class=\"MsoNormal\">A guideline from the .NET Framework team is that you never throw an exception  using the <b>System.Exception<\/b> class. You should use more specific exception types whether built-in types such as <b>InvalidOperationException<\/b> and <b> NullReferenceException<\/b> or your own application specific types. On the other hand, you should also resist the  temptation of having your own exception types sprinkled everywhere and even replacing analogous .NET Framework native  types. <\/p>\n<p class=\"MsoNormal\">When it comes to exceptions, you should be very specific about the  exception-type that you pick up and should also create instances providing as much information as possible. For example, <b>ArgumentNullException<\/b> is way more specific than <b>ArgumentException<\/b>. If the problem consists in an unexpected NULL parameter  then you should go for <b>ArgumentNullException<\/b>. Furthermore, be aware that any  exceptions come with a message. Provide details within the message as the message itself is targeted to developers.  Another parameter of exception types that is often neglected is the name of the parameter where the exception  occurred-mention it every time. It can be a lifesaver sometimes.<\/p>\n<h1>The OnException Method<\/h1>\n<p class=\"MsoNormal\">In ASP.NET MVC, any method of any controller runs under the aegis of a system  component known as the action invoker. The invoker runs all the code within a try\/catch block and simply re-throws a  thread-abort exception. For all other exceptions, instead, it goes through the list of registered action filters and  gives each a chance to recover from the exception. At the end of the loop, if the exception has not been marked as  handled, the exception originally caught is re-thrown. What happens next depends on whether you have other mechanism of  exception handling set to watch over the entire application. If none is in place, which is the default, users will  experience the ASP.NET classic yellow page of death or any other error page you arranged.<\/p>\n<p class=\"MsoNormal\">An action filter enabled to handle exceptions can be a separate class defined as  an action filter (inherit from the <b>ActionFilter<\/b> class) or it can simply be a  controller class that overrides the <b>OnException<\/b> method. This method is always invoked when an unhandled exception occurs in the course of the  action method. <\/p>\n<pre>protected override void OnException(ExceptionContext filterContext) \n{\n&#160;&#160; ...\n}<\/pre>\n<p class=\"MsoNormal\">It&#8217;s important to be aware that no exception that originates outside the  controller will be caught by <b>OnException.<\/b> An excellent example of an  exception not being caught by <b>OnException<\/b> is a &#8216;null reference&#8217; exception  that results in the model-binding layer. Another example is &#8216;route not-found&#8217; exception. <\/p>\n<p class=\"MsoNormal\">The code in<b> OnException<\/b> has the power of controlling the entire response for the request that failed. As shown above,  the method receives a parameter of type <b>ExceptionContext<\/b> which has an <b>ActionResult <\/b>property named <b>Result<\/b>.  This property just refers to the next view or result past the method. If you set the <b>Result <\/b>property you can control the next screen; if you omit setting any result, then the user will see just  a blank screen. Here&#8217;s a typical implementation of <b>OnException<\/b>:<\/p>\n<pre>protected override void OnException(ExceptionContext filterContext)\n{\n&#160;&#160;&#160; \/\/ Let other exceptions just go unhandled\n&#160;&#160;&#160; if (filterContext.Exception is InvalidOperationException)\n&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; \/\/ Default view is \"error\"\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; filterContext.SwitchToErrorView();\n&#160;&#160;&#160; }\n}<\/pre>\n<p class=\"MsoNormal\">The <b>SwitchToErrorView<\/b> method is an  extension method for the <b>ExceptionContext<\/b> class with the following signature:<\/p>\n<pre>public static void SwitchToErrorView(this ExceptionContext context, \n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; String view = \"error\", String master = \"\")<\/pre>\n<p class=\"MsoNormal\">As you can see, you&#8217;re allowed to indicate the next view and even its layout.<\/p>\n<h1>The HandleError Attribute<\/h1>\n<p class=\"MsoNormal\">If you don&#8217;t like the explicit override of<b>  OnException<\/b> you can decorate the class (or just individual methods) with the <b> HandleError<\/b> attribute.&#160; <\/p>\n<pre>[HandleError]\npublic class HomeController\n{\n&#160;&#160;&#160; ...\n}<\/pre>\n<p class=\"MsoNormal\">As mentioned, <b>HandleError<\/b> is an action filter and not a plain attribute carrying just a bunch of metadata. In particular, <b>HandleError<\/b> implements the<b>  IExceptionFilter<\/b> interface:<\/p>\n<pre>public interface IExceptionFilter\n{\n&#160;&#160; void OnException(ExceptionContext filterContext);\n}<\/pre>\n<p class=\"MsoNormal\">Internally, <b>HandleError <\/b>implements <b>OnException<\/b> using a piece of code very  similar to the <b>SwitchToErrorView <\/b>method discussed earlier. A minor difference  is that <b>HandleError<\/b> doesn&#8217;t trap any exceptions resulting from child actions. Properties on the attribute lets you  select the exceptions to trap and views to redirect to. <\/p>\n<pre>[HandleError(ExceptionType=typeof(ArgumentException), View=\"generic\")]<\/pre>\n<p class=\"MsoNormal\">Each method can have multiple occurrences of the attribute, one for each  exception you&#8217;re interested in. By default, also <b>HandleError<\/b> redirects to the  same view named <i>error<\/i> we considered earlier. Note that such a view is  purposely created by the ASP.NET MVC templates in Visual Studio.<\/p>\n<p class=\"MsoNormal\">When using <b>HandleError<\/b> at development time, it&#8217;s crucial to be aware that the attribute doesn&#8217;t have any effect unless  you enable custom errors at the application level: <\/p>\n<pre>&lt;customErrors mode=\"On\"&gt;\n&lt;\/customErrors&gt;<\/pre>\n<p class=\"MsoNormal\">When you go live, remote users will correctly receive the selected error page  regardless. To test the feature, though, you need to change the configuration file. <\/p>\n<p class=\"MsoNormal\"><b>HandleError<\/b>  can be automatically applied to any method of any controller class by registering it as a global filter in <b>global.asax<\/b>: <\/p>\n<pre>public class MvcApplication : System.Web.HttpApplication \n{\n&#160;&#160;&#160; protected void Application_Start()\n&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; RegisterGlobalFilters(GlobalFilters.Filters);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; ...\n&#160;&#160;&#160; }\n&#160;&#160;&#160; public static void RegisterGlobalFilters(GlobalFilterCollection filters)\n&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; filters.Add(new HandleErrorAttribute());\n&#160;&#160;&#160; }\n}<\/pre>\n<p class=\"MsoNormal\">Global filters are automatically added to the list of filters before the action  invoker calls out any action method.<\/p>\n<h1>All Other Possible Errors<\/h1>\n<p class=\"MsoNormal\">An error can always find its way to the user. For this reason, we&#8217;ve been given  the <b>Application_Error<\/b> method in <b>global.asax<\/b> &#160;ince the very first version of the ASP.NET runtime. It is just there to handle  any possible errors that passed through try\/catch blocks. The Error event fires whenever an unhandled exception reaches  the outermost shell of ASP.NET code. &#160;It&#8217;s the final call for developer&#8217;s code  before the yellow screen of death.<\/p>\n<p class=\"MsoNormal\">You could do something useful in this event handler, such as sending an email or  writing to the event log.&#160; <\/p>\n<pre>void Application_Error(Object sender, EventArgs e) \n{ \n&#160;&#160;&#160; var exception = Server.GetLastError();\n&#160;&#160;&#160; if (exception == null)\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; return;\n&#160;&#160;&#160; var mail = new MailMessage { From = new MailAddress(\"automated@contoso.com\") };\n&#160;&#160;&#160; mail.To.Add(new MailAddress(\"administrator@contoso.com\"));\n&#160;&#160;&#160; mail.Subject = \"Site Error at \" + DateTime.Now;\n&#160;&#160;&#160; mail.Body = \"Error Description: \" + exception.Message;\n&#160;&#160;&#160; var server = new SmtpClient { Host = \"your.smtp.server\" };\n&#160;&#160;&#160; server.Send(mail);\n\n&#160;&#160;&#160; \/\/ Clear the error\n&#160;&#160;&#160; Server.ClearError();\n\n&#160;&#160;&#160; \/\/ Redirect to a landing page\n&#160;&#160;&#160; Response.Redirect(\"home\/landing\");\n}<\/pre>\n<p class=\"MsoNormal\">While you can always write the Error handler yourself, ASP.NET developers often  use ELMAH. At the very end of the day, ELMAH is an HTTP module that, once configured, intercepts the Error event at the  application level and logs it according to the configuration of a number of back-end repositories. The bottom line is  that with ELMAH you can handle errors in many more ways and change \/add actions with limited work; and without writing  much code yourself. &#160;ELMAH also offers some nice facilities, such as a web page  you can use to view all recorded exceptions and drill down into each of them. &#160;<\/p>\n<p class=\"MsoNormal\">ELMAH is an open-source project available at <a href=\"http:\/\/code.google.com\/p\/elmah\">http:\/\/code.google.com\/p\/elmah<\/a>. It is so popular that it counts a number of  extensions, mostly in the area of repositories. To integrate it in your applications the easiest path you can take is  the Nuget package you find at <a href=\"http:\/\/www.nuget.org\/packages\/elmah\/1.2.2\"> http:\/\/www.nuget.org\/packages\/elmah\/1.2.2<\/a>. <\/p>\n<h1>Summary<\/h1>\n<p class=\"MsoNormal\">Error handling is one of the most bothersome parts of software development. One  of the reasons that developers avoid it is that it doesn&#8217;t seem to require much creativity. In this regard, I think that  ELMAH is emblematic. Nearly any developers knows that an HTTP module could do the trick of saving rewriting the same  code over and over again to send emails and log errors on ASP.NET sites. And I guess as many developers had, in the  past, a thought crossing their minds about writing a sort of simple but effective infrastructure for error handling and  reporting. That&#8217;s just what ELMAH is-and that&#8217;s what ASP.NET developers need. Oh well, in addition to ad hoc try\/catch  blocks in the code.<\/p>\n<\/p><\/div>\n","protected":false},"excerpt":{"rendered":"<p>ASP.NET MVC gives you more options in the way that you handle exceptions. Error handling isn&#8217;t intrinsically exciting, but there are many ways of avoiding the classic yellow page of death, even getting ELMAH to manage error handling for you.&hellip;<\/p>\n","protected":false},"author":221911,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[143538],"tags":[4143,4156,4157,5166],"coauthors":[],"class_list":["post-1792","post","type-post","status-publish","format-standard","hentry","category-dotnet-development","tag-net","tag-asp","tag-asp-net","tag-mvc"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1792","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/221911"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=1792"}],"version-history":[{"count":5,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1792\/revisions"}],"predecessor-version":[{"id":41021,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1792\/revisions\/41021"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=1792"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=1792"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=1792"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=1792"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}