Custom error page isn't shown when exception thrown - c#

I have setup a custom error handler to show diagnostic information to a user if a crash occurs. The problem is the custom error page is not shown and I get an exception (according to the webpage) thrown whilst trying to show the error page. I cannot figure out what is causing it though? I have similar pages set up for 500 and 404 errors which work fine.
The error page says Server Error in '/' Application.
Description: An exception occurred while processing your request. Additionally, another exception occurred while executing the custom error page for the first exception. The request has been terminated.
Ill show snippets of my setup, if anyone wants to see more please ask. FYI I am throwing the exception by removing the connection string details from my web.config (its an actual error we are seeing during deployment so I want to target this specifically)
<system.webServer>
<httpErrors errorMode="Custom">
<remove statusCode="404" />
<error statusCode="404" path="/error/notfound" responseMode="ExecuteURL" />
<remove statusCode="403" />
<error statusCode="403" path="/error/forbidden" responseMode="ExecuteURL" />
<remove statusCode="500" />
<error statusCode="500" path="/error/" responseMode="ExecuteURL" />
</httpErrors>
</system.webServer>
<!-- .... -->
<system.web>
<customErrors mode="On" defaultRedirect="~/Error" redirectMode="ResponseRewrite">
<error redirect="~/Error/NotFound" statusCode="404" />
<error redirect="~/Error/Forbidden" statusCode="403" />
<error redirect="~/Error/" statusCode="500" />
</customErrors>
</system.web>
I then have an ErrorController with a default Index() function (no breakpoint within this controller gets hit)
public ViewResult Index()
{
return View("Error");
}
Note: I have functions for Forbidden() and NotFound() - I just didnt copy them here - these errors work perfectly fine.

Do you have all those roots available you specified in web.config? Seems that your controller just have index action, returning some view, but it supposed to have NotFound and Forbidden actions as well, or at least correct routs such as:
routes.MapRoute(
"NotFound",
"Error/NotFound",
new { controller = "Error", action = "Index" }, //bind all routes to single action
null, controllerNamespaces
);
routes.MapRoute(
"Forbidden",
"Error/Forbidden",
new { controller = "Error", action = "Index" }, //bind all routes to single action
null, controllerNamespaces
);

If you don't have NotFound and Forbidden actions setup those errors are likely throwing a second exception that is going to your index page since it is the default. Trying adding those two others your controller and see if they get hit and perhaps you can find the problem easier.
Also note that ResponseRewrite isn't compatible with mvc, see the answer here: CustomErrors does not work when setting redirectMode="ResponseRewrite"

You cannot use redirectMode="ResponseRewrite" when redirecting to another action, you have to use redirectMode="ResponseRedirect". You will loose the ability to use Server.GetLastError(), but if you don't need that, you will be fine.

Related

Custom error pages in ASP.NET MVC 5

I want to add custom error pages to my project.
I found this post about my problem and i try to implement it.
So :
i add 404.cshtml, 404.html, 500.cshtml and 500.html pages
set response status code in added cshtml files
comment adding HandleErrorAttribute to global filters
update my web.config file
But now when i try to go by path http://localhost:120/foo/bar where my app is on http://localhost:120 i get next page :
Server Error in '/' Application.
Runtime Error
Description: An exception occurred while processing your request. Additionally, another exception occurred while executing the custom error page for the first exception. The request has been terminated.
I set <customErrors mode="Off" to see what problem is. It was - The resource cannot be found. which is logical. But when i set <customErrors mode="On" - i again get Runtime error.
What can cause it and how to solve it?
My config file :
<system.web>
<customErrors mode="Off" redirectMode="ResponseRewrite" defaultRedirect="~/500.cshtml">
<error statusCode="404" redirect="~/404.cshtml"/>
<error statusCode="500" redirect="~/500.cshtml"/>
</customErrors>
</system.web>
<system.webServer>
<httpErrors errorMode="Custom">
<remove statusCode="404"/>
<error statusCode="404" path="404.html" responseMode="File"/>
<remove statusCode="500"/>
<error statusCode="500" path="500.html" responseMode="File"/>
</httpErrors>
</system.webServer>
IIS version 8.5
What version of IIS are you using? If 7+ then ignore custom errors using <customErrors mode="Off"> and use <httpErrors>. Using the method below the latter will show your error page without changing the URL which IMO is the preferred way of handling these things.
Set up an Error Controller and put your 404 and 500 in there like so:
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="404" />
<remove statusCode="500" />
<error statusCode="404" path="/error/notfound" responseMode="ExecuteURL" />
<error statusCode="500" path="/error/servererror" responseMode="ExecuteURL" />
</httpErrors>
In the controller:
public class ErrorController : Controller
{
public ActionResult servererror()
{
Response.TrySkipIisCustomErrors = true;
Response.StatusCode = (int)HttpStatusCode.InternalServerError;
return View();
}
public ActionResult notfound()
{
Response.TrySkipIisCustomErrors = true;
Response.StatusCode = (int)HttpStatusCode.NotFound;
return View();
}
}
Then obviously set up the corresponding view for each error covered.
Your redirect url is not correct. Make it ~/404.html and ~/500.html. Notice that I changed the extension from .cshtml. Make sure the files exist and you are pointing to the correct location.
I had to do the following:
Remove the defaultPath from httpErrors and defaultRedirect from customErrors.
Make sure in Global.asax I had registered a default route:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { action = "Index", id = UrlParameter.Optional
});
I'm not sure why step 1 was necessary and step 2 was because we're doing EPiServer.

Can't redirect to custom error pages

I'm trying to redirect to a custom page when there's an error. So I added to the Web.Config the following code
<customErrors mode="On" redirectMode="ResponseRewrite" defaultRedirect="~/Views/Error/Error500.cshtml">
<error statusCode="404" redirect="~/Views/Error/Error404"/>
<error statusCode="500" redirect="~/Views/Error/Error500"/>
</customErrors>
</system.web>
<system.webServer>
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="404" subStatusCode="-1" />
<error statusCode="404" path="~/Views/Error/Error404" responseMode="ExecuteURL" />
<remove statusCode="500" subStatusCode="-1" />
<error statusCode="500" path="~/Views/Error/Error500" responseMode="ExecuteURL" />
</httpErrors>
But when I try localhost:23920/aFakeURl it redirects me to a blank page and it doesn't reach my ErrorController.
If I try localhost:23920/Error/Error404 it goes in my controller
// GET: /Error/Error404
public ActionResult Error404()
{
Response.StatusCode = 404;
return View();
}
then it returns a statusCode 404 and IIS doesn't know what to do with it and it gives me a blank page. So I'm pretty sure the problem is the path in the Web.Config.
I tried
~/Views/Error/Error404"
~/Views/Error/Error404.cshtml"
/Views/Error/Error404"
/Views/Error/Error404.cshtml"
It might be good to mention that when the path doesn't have a ~ it returns a runtime exception instead of a blank page.
So I have 2 questions.
What's the proper way to write the Web.Config?
Should I return the proper status code like this
Response.StatusCode = 404; in the ErrorController?
Thank you
I don't know if it's good to mention but I use Elmah for error handling and logging. No idea if it has something to do with this problem but I read in their documentation that it should work with mode="On". Is there a better way to handle all this?
EDIT
Now I use this
<customErrors mode="On" redirectMode="ResponseRewrite" defaultRedirect="/Error/Error500">
<error statusCode="404" redirect="/Error/Error404"/>
<error statusCode="500" redirect="/Error/Error500"/>
</customErrors>
</system.web>
<system.webServer>
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="404" subStatusCode="-1" />
<error statusCode="404" path="/Error/Error404" responseMode="ExecuteURL" />
<remove statusCode="500" subStatusCode="-1" />
<error statusCode="500" path="/Error/Error500" responseMode="ExecuteURL" />
</httpErrors>
but it always return an error 500 when I type a bad url.
The exception is System.Web.HttpException: The controller for path '/aBadUrllllll' was not found or does not implement IController.
How come this doesn't return a 404 error?
Do I have to change something in the Route.config?
Is ok to place the tag:
also you need specify the general errors codes and pages like this:
<system.webServer>
<httpErrors errorMode="Custom" existingResponse="Auto">
<remove statusCode="403" subStatusCode="14"/>
<error statusCode="403" subStatusCode="14" responseMode="ExecuteURL"
path="/App/Error/Forbidden"/>
<remove statusCode="404"/>
<error statusCode="404" responseMode="ExecuteURL" path="/App/Error/NotFound"/>
</httpErrors>...
Remember creates the page NotFound in the controller Error!
I was having similar issues and it was eventually resolved by ensuring I did all of the following:
1) customErrors mode="On" was set in web.config
2) Created an ErrorController with actions for specific errors that required a custom error page.
e.g.
[AllowAnonymous]
public virtual ActionResult NotFound(string message = "")
{
HttpContext.Response.StatusCode = 404;
return View();
}
3) Created a Filter.config file to add the HandleErrorAttribute and called this method in app start in global.asax.
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
4) Added global error handler in global.asax. Here's an incomplete sample of it.
void Application_Error(object sender, EventArgs e)
{
var exception = Server.GetLastError();
Response.Clear();
var httpException = exception as HttpException;
if (httpException != null)
{
var action = string.Empty;
switch (httpException.GetHttpCode())
{
case 401:
action = "Unauthorized";
break;
case 403:
action = "Forbidden";
break;
case 404:
action = "NotFound";
break;
case 500:
action = "ServerError";
break;
default:
action = "ServerError";
break;
}
Server.ClearError();
Response.Redirect(string.Format("~/Error/{0}/?message={1}", action, exception.Message));
}
Logger.Error("Unhandled website exception", exception);
}
With all this in place, then hard exceptions will be properly handled and intentional redirects, as well. For example, in cases upon login where a business rule was not met that prevented a user from proceeding, this was done.
return RedirectToAction("Unauthorized", "Error", new { message = "Your account is restricted from using this functionality." });
One word of advice, though, is that returning a 401 error will end up not displaying the error page and will take you to the login page, unless you handle it appropriately. I'm sure that is explained in some other post.
One other thing, and I just now discovered this when I deployed the latest to our Dev and UAT environments. In my local IIS, I was seeing the custom error pages just fine, but in other environments it was showing the default IIS pages. Routing to my ErrorController was working just fine, but the custom pages were still not showing. Turns out I needed this web.config entry
httpErrors existingResponse="PassThrough"
under system.webServer, which now makes sense.

Using customError page with /error address

I am trying to force my project to use custom made error page with /error address.
I did write ActionResult Error function in controller
public ActionResult Error()
{
return View();
}
made a simple View for Error
#{
ViewBag.Title = "Error Page";
}
<h1>ERROR</h1>
added an error route to global
routes.MapRoute(
"Error",
"Error/",
new { controller = "Home", action = "Error" }
);
and changed webconfig customErrors
<customErrors mode="On" defaultRedirect="Error">
</customErrors>
yet when I type non-existing url I get
Server Error in '/' Application. The resource cannot be found.
Description: HTTP 404. The resource you are looking for (or one of its
dependencies) could have been removed, had its name changed, or is
temporarily unavailable. Please review the following URL and make
sure that it is spelled correctly.
Requested URL: /Galery
Version Information: Microsoft .NET Framework Version:2.0.50727.1433;
ASP.NET Version:2.0.50727.1433
------>
what am I doing wrong.
Well if I type localpath/Error I can get to Error path and it works fine. Why the redirection is not working?
I am using VS2012 and server started by it.
You'll also have to override the <system.webServer> error block to catch IIS level errors:
<configuration>
<system.webServer>
<httpErrors errorMode="Custom" existingResponse="PassThrough">
<clear />
<error statusCode="502" path="/Error" responseMode="File" />
<error statusCode="501" path="/Error" responseMode="File" />
<error statusCode="500" path="/Error" responseMode="File" />
<error statusCode="412" path="/Error" responseMode="File" />
<error statusCode="406" path="/Error" responseMode="File" />
<error statusCode="405" path="/Error" responseMode="File" />
<error statusCode="404" path="/Error" responseMode="File" />
<error statusCode="403" path="/Error" responseMode="File" />
<error statusCode="402" path="/Error" responseMode="File" />
<error statusCode="401" path="/Error" responseMode="File" />
</httpErrors>
</system.webServer>
</configuration>
Errors and 404s are not the same thing. Your custom error thing will fire for unhandled exceptions, but a 404 is not considered to be an unhandled exception by the MVC framework. Create a "catch-all" route of "{*anything}" and route it to the error action method.
Also make sure you put this route as the VERY LAST ROUTE so the other routes aren't captured by it.

AspxErrorPath in Custom Error Page

We currently has a page that is used to display a generic error message when errors occur on our website. It has no functionality at all other than displaying a label that mentions there was an error.
Here is my issue, our client has ran a security review and tells us our error page contains phishing due to the URL in the query string, now I don't consider this a problem, but to put an end to the question, I'd like to remove the query string.
My web.config entry is this:
<customErrors mode="On" defaultRedirect="~/DefaultErrorPage.aspx">
</customErrors>
When an error occurs, it goes to DefaultErrorPage.aspx?aspxerrorpath=/Website1/LastPage.aspx
How can I prevent this? However, I could just redirect to the page if it contains the query, but I'm more looking for a way to prevent the query string instead of an extra redirection.
you could catch/handle all errors in your global.asax file instead and do the redirect there
protected void Application_Error(object sender, EventArgs e)
{
//Exception ex = Server.GetLastError();
Server.Transfer("~/DefaultErrorPage.aspx");
}
As a quick-fix, I've found that appending "?" onto the end of the defaultRedirect setting worked for me in removing the aspxerrorpath.
Also, I was getting the same issue with the customErrors settings in system.web, and the same solution worked:
<customErrors mode="On" defaultRedirect="~/SystemError.aspx">
<error statusCode="403" redirect="~/Home.aspx?"/>
<error statusCode="404" redirect="~/Home.aspx?"/>
</customErrors>
Alternatively, do the same on system.webServer settings:
<httpErrors errorMode="Custom">
<remove statusCode="403" subStatusCode="-1" />
<error statusCode="403" path="/Home.aspx?" responseMode="Redirect" />
<remove statusCode="404" subStatusCode="-1" />
<error statusCode="404" path="/Home.aspx?" responseMode="Redirect" />
</httpErrors>
You are going to have to take control of the error handling process yourself. One method is get rid of the custom error redirect and use the Application_Error method in global. You can then direct the person, as needed without any query string argument.
Another option is ELMAH, which is designed to avoid the yellow screen of death errors in ASP.NET. You can then tailor a friendly error and not worry about writing error handling code, per se.
A third method is to educate the security team on how ASP.NET works and see if the "security concern" is legitimate (it may be) or not. This does not mean they won't make you do one of the above options anyway, of course.

Add a web.config key for always redirect when get an unhandled exceptions

I once saw that was possible to do something like adding a key in the web.config file to redirect to a default error page everytime a unhandled exception is found.
Is it possible? how?
Yes the customErrors section of the web.config.
<customErrors defaultRedirect="~/GenericError.aspx" mode="On" />
This will redirect your users to what defaultRedirect (URL) when they encounter an error.
You can also specify where they go based on the HTTP response code
<customErrors defaultRedirect="~/GenericError.aspx" mode="On">
<error statusCode="500" redirect="~/Error.aspx"/>
<error statusCode="404" redirect="~/NotFound.aspx"/>
</customErrors>
Here is the documentation.
Add a CustomErrors section to your web.config.
<customErrors defaultRedirect="ErrorPage.aspx" mode="RemoteOnly" />
<customErrors defaultRedirect="~/serverErrorPage.aspx" mode="On" redirectMode="ResponseRewrite"/>
It's not suitable for real use prior to .NET3.5 service pack 1, as until then the redirectMode attribute wasn't there and it would always act with the default value "ResponseRedirect" which would redirect to the error page instead of showing it directly; so instead of giving an error response it would "successfully" redirect to another page, and then that would return the error!

Categories

Resources