I've been struggling all day to implement error handling in my ASP.NET MVC 2 app. I've looked at a variety of techniques, but none work properly. I'm using MVC2 and .NET 4.0 (started the project before MVC3 was released; we'll upgrade after we deliver our initial release).
At this point, I'll be happy to properly handle 404 and 500 errors -- 403 (authorization required) would be great, too, followed by various other specific responses. Right now, I either get all 404s, all 500s, all 302s before the 404, or all 302s before the 500.
Here are my requirements (which should be pretty close to the basic requirements of HTTP):
If a resource is not found, throw a 404, and display a 404-specific page with the requested URL. DO NOT return an intermediate response code like 302. Ideally, keep the requested URL, rather than showing a new URL like
/Error/NotFound
-- but if the latter displays, be sure we didn't return a redirect response to get it.If an internal server error occurred, throw a 500, and display a 500-specific error with some indication of what went wrong. Again, don't return an intermediate response code, and ideally don't change the URL.
Here's what I'd consider a 404:
- Static file not found:
/Content/non-existent-dir/non-existent-file.txt
- Controller not found:
/non-existent-controller/Foo/666
- Controller found, but Action not found:
/Home/non-existent-action/666
- Controller and action found, but the action can't find the requested object:
/Home/Login/non-existent-id
Here's what I'd consider a 500:
- Post a bad value:
POST /User/New/new-user-name-too-long-for-db-column-constraint
- Non-data-related problem, like a Web Service endpoint not responding
Some of these problems need to be identified by specific controllers or models, and then the controllers should throw the appropriate HttpException. The rest should be handled more generically.
For 404 case #2, I tried to use a custom ControllerFactory to throw a 404 if the controller can't be found.
For 404 case #3, I've tried to use a custom base controller to override HandleUnknownAction
and throw a 404.
In both cases, I get a 302 before the 404. And, I never get 500 errors; if I modify Web.config to put a typo in my Web Service endpoint, I still get a 302, then a 404 saying the URL (controller/action) which uses the Web Service can't be found.
I also get the requested URL as a(n unwanted) querystring param: /Error/NotFound?aspxerrorpath=/Home/non-existent-action
Both of these techniques came from http://www.niksmit.com/wp/?p=17 (How to get normal 404 (Page not found) error pages using ASP.Net MVC), pointed to from http://richarddingwall.name/2008/08/17/strategies-for-resource-based-404-errors-in-aspnet-mvc/
If in Web.config I have <customErrors mode="On" defaultRedirect="~/Error/Unknown" redirectMode="ResponseRedirect" />
, I get the appropriate response code, but my Error controller never gets called. Taking out the redirectMode
attribute gets me the MVC error views, but with an intervening 302 and a changed URL -- and always the same controller (Unknown
= 500; if I change it to NotFound
everything looks like a 404).
Here are some of the other things I've read and tried to implement:
- http://www.davidjuth.com/asp-net-mvc-error-handler.aspx
- http://sanjayuttam.com/wordpress/index.php/c-sharp/c-sharp-code-examples/error-handling-in-asp-net-mvc-1-part-2-of-2/
- http://blog.hebbink.com/post/2010/12/14/NET-custom-404-error-page-returns-302-for-http-status.aspx
- http://blog.dantup.com/2009/04/aspnet-mvc-handleerror-attribute-custom.html
- http://weblogs.asp.net/scottgu/archive/2008/07/14/asp-net-mvc-preview-4-release-part-1.aspx
.. along with a bunch of StackOverflow posts.
Seems to me this sort of error handling is pretty basic to Web apps, and the MVC framework ought to have defaults that do this out of the box, and let people extend it to work otherwise. Perhaps they'll do it in a future release. In the meantime, can someone give me comprehensive details on how to implement proper HTTP responses?
This doesn't answer your question, but it is important to note that HTTP status 500 indicates that something went wrong on the server, so your example:
Is not valid grounds to throw a 500, its a data validation issue and should be handled by MVC data annotations or a jQuery validation framework or etc. Just showing an error message next to the TextBox saying "User Name too long" is much better.
This is a very old question. but I thought It's worth it if I introduce you to a much much cleaner way to handle Http Exceptions that I saw in dear "Jesse Webb's answer".
The solution is to use the
httpErrors
element of thesystem.webServer
section:You also can log all exceptions in this way. "Read the "Jesse Webb's answer"".
This really feels much cleaner and also works as well as every other solution (without redirect).
Note: This only works work in IIS 7 and and newer. (Because of the
httpErrors
element which was recently added.Here's one technique you could use. Define an
ErrorsController
which will serve the error pages:and then in
Global.asax
you could subscribe for theApplication_Error
event where you could log the exception and execute the corresponding action of theErrorsController
:And now all that's left is to start throwing proper exceptions:
For HTTP 404 errors (without redirects) take a look at my blog post on the subject. This might give you some good ideas:
http://hectorcorrea.com/blog/returning-http-404-in-asp-net-mvc/16