When an error occurs in my ASP.NET MVC 4 application, I would like to customize a view for the user depending on the type of error. For example, page not found or an exception has occurred (with some user-friendly details about the exception). I've checked other examples of how to do this on StackOverflow and other online sources, but none of the answers are working for me.
The basic [HandleError] attribute does not seem to be working in VS2012 with an MVC 4 application targeting .NET 4.5. Here is the code I have in my home controller:
[HandleError]
public ActionResult Index()
{
Response.TrySkipIisCustomErrors = true; //doesn't work with or without this
throw new NullReferenceException("Uh oh, something broke.");
}
It is just throwing an exception, and I would expect the default ~/Shared/Error.cshtml view to be returned because of the [HandleError] attribute, but all I get is an HTTP 500 Internal Server Error indicating that the page could not be displayed. I checked my web.config, and different configurations seem to be behaving weird. In the section, it currently contains:
<customErrors mode="On" />
(I've tried adding defaultRedirect and with customErrors mode="Off" as well but that didn't have any effect... neither the shared Error view or the CustomError view I have is being rendered. If I change customErrors mode to off, then I can see the exception details as expected, so it is throwing the "Uh oh, something broke" exception properly.
I've also tried adding an OnException handler to the HomeController, and although I can debug through and see that the OnException event is being raised, it doesn't make any difference:
protected override void OnException(ExceptionContext filterContext)
{
base.OnException(filterContext);
filterContext.ExceptionHandled = true;
if (filterContext == null)
{
filterContext.Result = View("CustomError");
return;
}
Exception e = filterContext.Exception;
// TODO: Log the exception here
ViewData["Exception"] = e; // pass the exception to the view
filterContext.Result = View("CustomError");
}
I have also tried changing [HandleError] to specify a view, but that doesn't seem to do anything either:
[HandleError(View="CustomError")]
Any help would be much appreciated. Please let me know if you need any more details.
Another way to handle controller level exceptions is by overriding the OnException() method in the controller class. This method handles all your unhandled errors with error code 500. It allows you to log an exception and redirect to the specific view. It does not require to enable the <customErrors> config in web.
ASP.Net MVC has an attribute called "HandleError" that provides built-in exception filters. The HandleError attribute in ASP.NET MVC can be applied over the action method as well as Controller or at the global level. The HandleError attribute is the default implementation of IExceptionFilter.
We can add multiple HandleError attributes on the Controller (or on its actions methods) to handle exceptions. This approach will handle exceptions on Controller level. Conclusion: We have various ways of handling exceptions in ASP.NET MVC.
In ASP.NET MVC, Exception Filter is the major approach for exception handling, while for ASP.NET Core MVC, as Microsoft suggested, the built-in exception hadling middleware, UseExceptionHandler, is more flexible and suitable. IExceptionFilter Interface for ASP.NET is derived by System.
Finally, I would like to make a point that our discussions in this article, Exception Handling for ASP.NET Core MVC, are suitable for ASP.NET Core Web app, because the structure of ASP.NET Core MVC app and ASP.NET Core Web app are quite similar. If we compare the startup file for both Core MVC app and Core Web app, we can see that:
Learn more about handling exceptions using web.config customErrors in ASP.NET MVC . The HandleErrorAttribute is an attribute that can be used to handle exceptions thrown by an action method or a controller. You can use it to display a custom view on a specific exception occurred in an action method or in an entire controller.
I also went on a seamingly endless journey of reading SO answers and assorted blog postings trying to get custom error pages to work. Below is what finally worked for me.
The first step is to use IIS Express for debugging instead of the built-in Cassini web server to "guarantee" that the debug experience will mirror the live environment.
Create a controller to handle application errors and add an action for each custom error you will handle. The action should do any logging, set the status code, and return the view.
public class ErrorsController : Controller
{
// 404
[HttpGet]
public ActionResult NotFound()
{
Response.StatusCode = (int)HttpStatusCode.NotFound;
return View();
}
// I also have test actions so that I can verify it's working in production.
[HttpGet]
public ActionResult Throw404()
{
throw new HttpException((int)HttpStatusCode.NotFound, "demo");
}
}
Configure the customErrors
section in web.config to redirect to your custom error actions.
<system.web>
<customErrors mode="RemoteOnly" defaultRedirect="Errors/InternalServerError">
<error statusCode="400" redirect="Errors/BadRequest" />
<error statusCode="403" redirect="Errors/Forbidden" />
<error statusCode="404" redirect="Errors/NotFound" />
<error statusCode="500" redirect="Errors/InternalServerError" />
</customErrors>
Add the httpErrors
section to system.webServer
and set the errorMode to Detailed in web.config. Why this works is a mystery to me, but this was the key.
<system.webServer>
<httpErrors errorMode="Detailed" />
Add a catchall route last to the defined routes to direct 404s to the custom page.
// catchall for 404s
routes.MapRoute(
"Error",
"{*url}",
new {controller = "Errors", action = "NotFound"});
You may also want to create a custom HandleErrorAttribute
and register it as a global filter to log 500 errors.
These steps worked for me in both development (IIS Express) and production (IIS7) environments. You need to change customErrors mode="On"
to see the effect in development.
I seem to recall that you had to call the page from a non-localhost IP address (typically another computer). And it has to be an IIS based server, not the built-in development server (so IIS or IIS Express, but then you have to configure IIS Express for external access, which is a pain).
You can in fact debug it, you have to configure your local server on your debug computer to accept external requests, then call your local server from the remote server.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With