I have the following code in global.asax which transfers to a static NotFound.aspx file when there is a 404 exception. This works on my development machine, with debug or release builds. When deploying the release build to an azure app service, instead of getting my static NotFound.aspx file I get a page with only the text: The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.
I have verified that the static files are present on the azure deployment.
The code in global.asax is:
protected void Application_Error(object sender, EventArgs e)
{
Exception exception = Server.GetLastError();
Response.Clear();
HttpException httpException = exception as HttpException;
if (httpException != null)
{
ErrorLogger.Log(httpException);
Server.ClearError();
switch (httpException.GetHttpCode())
{
case 404:
// page not found
Response.StatusCode = 404;
Server.Transfer("~/NotFound.aspx");
break;
default:
Response.StatusCode = 500;
Server.Transfer("~/Error.aspx");
break;
}
}
}
The problem seems to be that the Azure server environment has it's httpErrors config section defined in a way that intercepts these errors before they get to Application_Error. You can either modify this to let the errors pass through, or use it to deal with the errors in the first place (Which seems to be the best option). Using responseMode="File" you can avoid having to issue a redirect, and just supply a custom error page and the proper status code directly. This seems to be a more efficient and correct approach.
Example:
<system.webServer>
<httpErrors errorMode="Custom" existingResponse="Replace" >
<remove statusCode="404"/>
<error statusCode="404" path="NotFound.html" responseMode="File"/>
<remove statusCode="500"/>
<error statusCode="500" path="Error.html" responseMode="File"/>
<remove statusCode="400"/>
<error statusCode="400" path="Error.html" responseMode="File"/>
</httpErrors>
</system.webServer>
For more info:
https://www.iis.net/configreference/system.webserver/httperrors
You could also try specifying the redirect rule in the Web.config:
<configuration>
<system.webServer>
<httpErrors errorMode="DetailedLocalOnly" existingResponse="PassThrough">
<remove statusCode="404"/>
<add statusCode="404" path="/NotFound.aspx" responseMode="Redirect" />
</httpErrors>
</system.webServer>
</configuration>
Then in your Web.Release.config(or other configuration you use in Azure):
<configuration>
<system.webServer>
<httpErrors errorMode="DetailedLocalOnly" existingResponse="Replace" xdt:Transform="SetAttributes">
</httpErrors>
</system.webServer>
</configuration>
You can add your code 500 error page in a similar fashion.
Setting responseMode to Redirect makes IIS redirect the user with a 302, setting it to ExecuteURL will replace the response with the error page but keep the URL in the address bar.
Here is nice article about handling errors in this way: http://tedgustaf.com/blog/2011/5/custom-404-and-error-pages-for-asp-net-and-static-files/
Related
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.
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.
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.
This is my first post here, and I have searched for a resolution to this issue here and at many other forums on the web, without success.
I am attempting to create a custom error for directory access denied errors 403.14 for cases where say if someone tries to load the "_assests" directory on a web site. I know I can do a work around by adding a default.aspx page to each directory that I want this to happen with, but was wondering if there is a site wide solution similar to the tag in the web.config file
<configuration>
<system.web>
<customErrors defaultRedirect="/Errors/GenericError.aspx" mode="RemoteOnly">
<error statusCode="401"
redirect="/Errors/401.aspx"/>
<error statusCode="403"
redirect="/Errors/403.aspx"/>
<error statusCode="404"
redirect="/Errors/404.aspx"/>
<!--
<error statusCode="403.14"
redirect="/"/>
-->
</customErrors>
</system.web>
</configuration>
I get the error when coding the web.config that I am unable to use a statusCode with a decimal in it because it's not a datatype Int
I have an IIS 7 on Server 2008.
Any ideas?
Apologies ahead of time if this sounds rather confusing. Happy to clarify.
Added the following to the web.config and it seems to work so far. Don't know why, but if I don't explicitly tell 403 errors to redirect to a custom 403.aspx page, instead of the GenericError.aspx page, I get a 500 error. However, if I redirect 404 errors to my custom 404.aspx page, the GenericError.aspx code is written in place, not as expected, and it seems you are never redirected to the actual 404.aspx page (see commented portion of web.config). Bizarre.
CODE:
web.config file:
<system.webServer>
<httpErrors existingResponse="Replace" errorMode="Custom">
<remove statusCode="403"/>
<remove statusCode="404"/>
<error statusCode="403" path="/Errors/403.aspx" responseMode="Redirect" />
<!-- <error statusCode="403" path="/Errors/GenericError.aspx" responseMode="Redirect" /> -->
<!-- <error statusCode="404" path="/Errors/GenericError.aspx" responseMode="Redirect" /> -->
<error statusCode="404" path="/Errors/404.aspx" responseMode="Redirect" />
</httpErrors>
</system.webServer>
GenericError.aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
var ex = HttpContext.Current.Server.GetLastError();
if (ex is HttpException)
{
var nex = ex as HttpException;
//Label in the Main code displays the Error Code from the Error String
this.customErrorMessageCode.Text += "Error Code" + " " + nex.GetHttpCode().ToString();
//Label in the Main code displays the Error Message from the Error String
this.customErrorMessageLabel.Text += ex.Message.ToString();
//DIV ID in the Main code displays the entire error message
this.customErrorMessage.Visible = true;
switch (nex.GetHttpCode())
{
case 404:
this.customErrorMessageCode.Text += " Page Not Found";
this.customErrorMessageImage.Visible = true;
// do somehting cool
break;
case 403:
this.customErrorMessageCode.Text += " Forbidden Access";
this.customErrorMessageImage.Visible = true;
// do somehting cool
break;
case 500:
this.customErrorMessageCode.Text += " Internal Error";
this.customErrorMessageImage.Visible = true;
// do somehting cool
break;
default:
break;
}
}
else {
this.customErrorMessageLabel.Text += ex.Message + ex.GetType().ToString();
}
}
SOURCE:
CustomError in web.config
Perhaps you could use a redirection approach that is based on the actual error code using Server.GetLastError().
In the Global.asax you will have something like this:
protected void Application_Error(object sender, EventArgs e)
{
if (Context.IsCustomErrorEnabled) {
ShowCustomErrorPage(Server.GetLastError());
}
}
ShowCustomErrorPage would then have a switch statement that reads the HTTP code and redirects to the correct error page.
The is more from the source link, but it might be too MVC specific. As you didn't mention you use MVC, I didn't want to assume and blindly copy-paste.
I am not too familiar with MVC, but the principles here look like they could be adjusted to suit your scenario.
Source: http://www.digitallycreated.net/Blog/57/getting-the-correct-http-status-codes-out-of-asp.net-custom-error-pages
Edit
Found a couple of StackOverflow posts that could help too:
Custom Error Handling in web.config / Global.asax not handling non-existant directory
Custom error handling Asp.Net
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.