This was caused partly due to my misunderstanding of how custom errors are actually invoked and also the fact that (IMHO), the handling of errors in asp.net mvc is a bit messed up.
The first issue was that in a number of my action methods, I was checking for the existence of an object e.g. a blog post, and returning a HttpNotFoundResult if the blog post was null. I was under the assumption that this would then display the custom error page that I had set up for 404 errors.
However, this is not the case. Returning a HttpNotFoundResult simply sets the status code of the response to 404. The rest is then handled by IIS, displaying the IIS 404 error page or by your browser if it has it's own custom error page.
One solution here is to return a HttpException which will use your custom error pages since the request is be handled by asp.net.
I chose instead to create a new ActionResult that allowed me to specify a view along with a http status code. I preferred this to throwing exceptions.
The next issue was that by default a new MVC project has a greedy route defined. If you make a request to /foo/bar
the default MvcHandler will look for a controller called Foo
. When it can't find it, it will return 404.
I had removed the default route and had no greedy routes. This meant that urls not matching any of my routes would not be handled by asp.net and would just fall back to IIS.
The solution here was to create a wildcard route at the bottom of my routing configuration to match all other requests and forward them to a custom PageNotFound action, that sets the status code to 404 and displays my custom view.
Some things worth pointing out.
- You will need to set
httpErrors errorMode="Detailed"
for your custom error pages to be displayed in IIS/IISExpress. The rest however can be left alone.
- Setting the
defaultRedirect
path in the customErrors
section has no effect on 500 errors. This is because the global HandleErrorAttribute
handles all 500 errors and just looks for a view called "Error" to display. This means that if your custom error page is actually a controller action, it will not be invoked. The above is true even if you explicitly specify a 500 error page.
- You should still keep the defaultRedirect path however, as it will be used for other status codes if they are not specified explicitly.