I've been trying to configure custom error pages for my web application using [HandleError] attributes. While trying to configure my application I've noticed a few things which I thought I should share, which weren't obvious, for me at least.
HandleError is meant to be a way to specify a view to display when a specific exception is thrown. In my case I wanted a "permission denied" view to be displayed when an user didn't have the correct permissions to view/invoke an action on a controller.
So far I've noticed these things:
CustomErrors in web.config must be Off
For the HandleError attribute to intercept the exception the customErrors config value in web.config must be set to Off. Otherwise the exception message and complete stack trace is shown and not the custom view.
Ordering of attributes
The order of the attributes you specify on your controller impacts the way ASP.NET MVC chooses the view to display. For example:
1: [HandleError]
2: [HandleError(View = "PermissionDenied", ExceptionType = typeof(PermissionDeniedException))]
3: public class OCABController
4: : Controller
5: {
6: public ActionResult test()
7: {
8: throw new PermissionDeniedException();
9: }
10: }
The result of the PermissionDeniedTest() method would be that the ASP.NET MVC would display the "PermissionDenied" view. Any other exception and the default "Error" view would be displayed.
The problem is that if you change the order the attributes are specified. For example:
1: [HandleError(View = "PermissionDenied", ExceptionType = typeof(PermissionDeniedException))]
2: [HandleError]
3: public class OCABController
4: : Controller
5: {
6: public ActionResult test()
7: {
8: throw new PermissionDeniedException();
9: }
10: }
Then the default "Error" view would be displayed, just because the order of the HandleError attributes is different.
Don't throw exceptions that would result in an non-HTTP 500 error code
My first attempt for displaying a "PermissionDenied"-view when a user tried to perform something which he didn't had the permission for was to throw an UnauthorizedAccessException. While just trying this out I couldn't get the HandleError attribute to pick up the exception. None of the HandleError attributes picked up the exception and displayed a custom error page. Instead it gave me the call stack and exception message. While debugging the ASP.NET MVC code to try to figure out why it didn't display a custom view I found the answer in HandleErrorAttribute.cs.
1: // If this is not an HTTP 500 (for example, if somebody throws an HTTP 404 from an action method),
2: // ignore it.
3: if (new HttpException(null, exception).GetHttpCode() != 500) {
4: return;
5: }
Basically it means that any exceptions that would case a non-HTTP 500 error is ignored.
It's possible to decorate a base class with [HandleError]
I've created a base class which inherits from the Controller class. All my controllers inherit from my base controller. This way I can control some common decisions. One of those is which view gets displayed for which exception. In my case I just need to display a "PermissionDenied"-view when a user tries to do something he doesn't have permission to do. Using IAuthorizationFilter to throw a PermissionDeniedException when an user tries to do something which he lacks the permissions to do and setting up an HandleError attribute in my base class with the ExceptionType = typeof(PermissionDeniedException) I can remove some duplicated code and be sure that each Controller behaves the same way.
Currently rated 4.0 by 1 people
- Currently 4/5 Stars.
- 1
- 2
- 3
- 4
- 5