How to return 'own' 404 custom page? - asp.net

In case if error occurred on my web site I do the following:
Server.Transfer("/error.aspx");
and that page has code:
protected void Page_Load(object sender, EventArgs e)
{
...
Response.StatusCode = 404;
}
If I work on the localhost then together with 404 status returned for the page, page displays 'proper error description'.
Once I published the same code to the internet all pages with errors are still displayed with 404 status code, but the don't have the content. Instead, they have the standard 404 error message:
404 - File or directory not found.
if the line "Response.StatusCode = 404" commented out then the proper page is provided, but it has 200 status code.
Question: how to return user-friendly error page that in the same time has 404 error status code?
Any thoughts are welcome! Thanks a lot in advance!
P.S. ASP.NET 4.0

<customErrors mode="On" defaultRedirect="~/Error/GenericErrorPage.aspx">
<error statusCode="404" redirect="~/Error/404.aspx" />
</customErrors>
http://msdn.microsoft.com/en-us/library/h0hfz6fc(v=vs.71).aspx
http://msdn.microsoft.com/en-us/library/aa479319.aspx

A ha!
Try this:
Response.TrySkipIisCustomErrors = true;
Response.Status = "404 Not Found";
Response.StatusCode = 404;
I found as soon as I added Response.TrySkipIisCustomErrors=true before setting the status code, I would see the normal page copy AND a 404 is returned. Without this line the standard IIS 404 page is displayed.
Alternatively, this can be set in the web.config like so:
<system.webServer>
<httpErrors existingResponse="PassThrough">
// custom error page mappings
</httpErrors>
</system.webServer>
The key thing here is existingResponse="PassThrough"
This was added to IIS7 thus is required on sites running in Integrated Pipeline mode.
For more info: http://msdn.microsoft.com/en-us/library/system.web.httpresponse.tryskipiiscustomerrors.aspx
Update
Updating for clarrification/more info as people are still finding this useful.
It's worth noting that if you need a simple, generic 404 page use the web.config method (and best make it a plain HTML page).
The method I describe works best if you have a heavily dynamic or CMS driven site where any given page could potentially return a 404 but you want to show your visitor related info.
For example, a special offers page (offers/some-offer) could do a lookup for the offer (some-offer) and if it doesn't exist show alternative or related offers while returning a 404 under the bonnet. As far as the visitor is aware they've just been told the offer is no longer available but they're still in the offers section but we're also telling robots to un-index the URL.
This would be a lot harder to do if there was just one generic 404 page.

You can achieve this by configuring your web.config file. Please check the link below to an article, which explains at the bottom of the page, how to display different custom error pages for different HTTP error statuses.
Displaying a Custom Error Page

To show your own page with the correct 404 statuscode, you can use the following code:
1) In your web.config add the following:
<customErrors mode="On" redirectMode="ResponseRewrite">
<error statusCode="404" redirect="404.htm" />
</customErrors>
and:
<httpErrors errorMode="Custom">
<remove statusCode="404"/>
<error statusCode="404" path="404.htm" responseMode="File"/>
</httpErrors>
2) Add a 404.htm file to the root of your website:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>404 - Not Found</title>
<meta http-equiv="refresh" content="5;url=/404-PAGE" />
</head>
<body>
CONTENT
</body>
</html>
You can either add content to the body of this file and remove the META refresh or simply use the META refresh to open a page within your CMS.

Combining Jag's and adt's answers, I still had a problem. When a 404 was handled by the static file handler (as opposed to ASP.NET), I got a blank response. (The status was correctly 404.)
To fix it, I had to add errorMode="Custom" to the <httpErrors> element. If your error page uses ASP.NET, you need to include responseMode="ExecuteURL".
<system.web>
<customErrors mode="On" defaultRedirect="~/Error.aspx" redirectMode="ResponseRewrite" />
</system.web>
<system.webServer>
<httpErrors errorMode="Custom">
<remove statusCode="404" />
<error statusCode="404" path="/Error.aspx" responseMode="ExecuteURL" />
</httpErrors>
</system.webServer>

<httpErrors errorMode="Custom">
<remove statusCode="404"/>
<error statusCode="404" path="ErrorPages/error404.htm" responseMode="Redirect"/>
</httpErrors>
This works for me if I don't use the tilde (~) in the path attribute

For anyone wondering in ASPNET 6.0+ you can now use the following official solution [1]
In Program.cs:
app.UseStatusCodePagesWithReExecute("/StatusCode", "?statusCode={0}");
In StatusCode.cshtml.cs
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public class StatusCodeModel : PageModel
{
public int OriginalStatusCode { get; set; }
public string? OriginalPathAndQuery { get; set; }
[ViewData]
public string Code { get; set; } = "";
public void OnGet(int statusCode)
{
OriginalStatusCode = statusCode;
Code = statusCode.ToString();
var statusCodeReExecuteFeature =
HttpContext.Features.Get<IStatusCodeReExecuteFeature>();
if (statusCodeReExecuteFeature is not null)
{
OriginalPathAndQuery = string.Join(
statusCodeReExecuteFeature.OriginalPathBase,
statusCodeReExecuteFeature.OriginalPath,
statusCodeReExecuteFeature.OriginalQueryString);
}
}
}
In StatusCode.cshtml (here is where you can customize to your sites theme)
#page
#model StatusCodeModel
Its a Custom Page for Status Code: #ViewData["Code"]
[1] https://learn.microsoft.com/en-us/aspnet/core/fundamentals/error-handling?view=aspnetcore-6.0#usestatuscodepageswithreexecute

To create & access 404 page in asp.net C# follow the steps:
1)create an 404.html file & add your content
<html>
<head>
<meta charset="utf-8" />
<title>404 - Not Found</title>
<link href="bootstrap/css/bootstrap.css" rel="stylesheet" />
<link href="bootstrap/css/bootstrap.min.css" rel="stylesheet" />
<style>
body {
color: #797979;
background: #eaeaea;
font-family: 'Ruda', sans-serif;
padding: 0px !important;
margin: 0px !important;
font-size: 13px;
}
.p404 img {
margin-top: 120px;
}
.centered {
text-align: center;
}
.p404 h1 {
font-weight: 900;
}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-lg-6 col-lg-offset-3 p404 centered">
<img src="assets/img/404.png" alt="">
<h1>DON'T PANIC!!</h1>
<h3>The page you are looking for doesn't exist.</h3>
<br>
<div class="row">
<div class="col-md-8 col-md-offset-2">
<a class="btn btn-success" href="Default.aspx">Back To Home</a>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
in web config add this code
<system.web>
<customErrors mode="On" redirectMode="ResponseRewrite">
<error statusCode="404" redirect="404.html" />
</customErrors>
</system.web>
<system.webServer>
<httpErrors errorMode="Custom">
<remove statusCode="404"/>
<error statusCode="404" path="404.html" responseMode="File"/>
</httpErrors>
</system.webServer>

Related

How can i get original method and uri of request when handling errors in ASP.NET MVC 5

I want to handle all 404 errors with one page which shows method and uri of endpoint , that cause the error .
I'he made this controller .
public class ErrorController : Controller
{
public ActionResult NotFound()
{
Response.StatusCode = 404;
ViewBag.Message = $"{Request.HttpMethod} {Request.Url} not supported";
return View();
}
}
And in Web.Config
<system.webServer>
<httpErrors errorMode="Custom" existingResponse="Replace" >
<remove statusCode="404"/>
<error statusCode="404" path="/Error/NotFound" responseMode="ExecuteURL"/>
</httpErrors>
</system.webServer>
and view of error-page
<!DOCTYPE html>
<html lang="ru">
<head>
</head>
<body>
<h1>#ViewBag.Message</h1>
</body>
</html>
But request is different , so i lost original url and method. How can i change it?

Serving Up Pages for HTTP Status Codes

I'm trying to set up 500 and 404 pages for an ASP.NET 4.5.2 Web Forms project. I've got the 404 working when the non-existent page is a .ASPX page. - I have code written to serve up a custom NotFound.aspx page in response.
My problem occurs when I am using the Web.config to serve up a 404.html page for non-existent HTML pages. My 404.html page is in the root folder. If I test this with a non-existent HTML page in the root folder, 404.html renders correctly. However, if I test it with a non-existent HTML page in a non-existent sub-folder, the 404.html is served up, but the CSS/JS paths are no longer correct? It's like it's treating the CSS/JS paths as being relevant to the non-existent sub-folder I'm specifying as part of the test?
Global.asax.cs:
void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
if (ex != null && ex is HttpUnhandledException)
{
Server.ClearError();
Server.Transfer("~/Error.aspx", true);
}
if (ex != null)
{
var httpException = ex as HttpException;
if (httpException.GetHttpCode() == 404)
{
Server.ClearError();
Server.Transfer("~/NotFound.aspx", true);
}
}
}
Web.config:
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="404" />
<error statusCode="404" path="404.html" responseMode="File" />
</httpErrors>
Use absolute URLs for the CSS/JS paths. For example, in your 404.html (bootstrap and jquery are just examples):
<link href="/Content/bootstrap.min.css" rel="stylesheet" />
<script src="/Scripts/jquery-3.0.0.min.js"></script>
<script src="/Scripts/bootstrap.min.js"></script>
Another setup would be to set responseMode="Redirect":
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="404" />
<error statusCode="404" path="/Errors/404.html" responseMode="Redirect" />
</httpErrors>
In this example, 404.html is in folder Errors and the URLs can be relative:
<link href="../Content/bootstrap.min.css" rel="stylesheet" />
<script src="../Scripts/jquery-3.0.0.min.js"></script>
<script src="../Scripts/bootstrap.min.js"></script>
and that will work because the redirect URL is no longer relative to whatever URL you've requested.
I was able to solve it as follows:
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="404" />
<error statusCode="404" path="http://localhost/myproject/404.html"
responseMode="File" />
</httpErrors>
The key takeaway is that the path must be absolute for this version to work. So my next step would be to try and set the path programmatically so that in debug mode it would go to my local and in release mode go to the production URL. I don't want to mess with Web.config transform files.
If anyone has any further info, please feel free.

Http 500 error causes blank page in deployed MVC application

I am having a bit of an issue here. I have an MVC application that has been deployed to IIS 7 on Windows Server 2008. In Visual Studio 2012, whenever an internal server error occurs i.e. http 500, it shows the page I designed for it. However, when I deploy it to IIS, it shows a blank page which could be very annoying because one does not see the application's page at all. All I need is for the error page to display instead of the blank page that it currently displays as a deployed application in the client's site. I can then work on fixing the error in Visual Studio. Kindly pardon me if I broke any rules of S.O.
Here is what I have setup in my ErrorController.cs
public ActionResult ForbiddenPage()
{
Response.StatusCode = 403;
Response.TrySkipIisCustomErrors = true; // add this line
return View();
}
//
// GET: /Error/
public ActionResult PageNotFound()
{
Response.StatusCode = 404;
Response.TrySkipIisCustomErrors = true; // add this line
return View();
}
//
// GET: /Error/
public ActionResult InternalServerError()
{
Response.StatusCode = 500;
Response.TrySkipIisCustomErrors = true; // add this line
return View();
}
In web.config, this is what I have:
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<modules runAllManagedModulesForAllRequests="true" />
<handlers>
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." ...
</handlers>
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="403" />
<error statusCode="403" responseMode="ExecuteURL" path="/Error/ForbiddenPage" />
<remove statusCode="404" />
<error statusCode="404" responseMode="ExecuteURL" path="/Error/PageNotFound" />
<remove statusCode="500" />
<error statusCode="500" responseMode="ExecuteURL" path="/Error/InternalServerError"/>
</httpErrors>
</system.webServer>
My RouteConfig.cs Looks like this
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "LogIn",id = UrlParameter.Optional }
);
routes.MapRoute(
"403-ForbiddenPage",
"{*url}",
new { controller = "Error", action = "ForbiddenPage" }
);
routes.MapRoute(
"404-PageNotFound",
"{*url}",
new { controller = "Error", action = "PageNotFound" }
);
routes.MapRoute(
"500-InternalServerError",
"{*url}",
new { controller = "Error", action = "InternalServerError" }
);
The View that should be displayed is below:
#{
ViewBag.Title = "Internal Server Error";
Layout = "~/Views/Shared/_LayoutError.cshtml";
}
<h2></h2>
<div class="list-header clearfix">
<span>Internal Server Error</span>
</div>
<div class="list-sfs-holder">
<div class="alert alert-error">
An unexpected error has occurred.... click<a href ="/Home/LogIn"><i><u>here</u></i>
</a> to login again..
</div>
</div>
If there is any thing that I should have included to aid you in proffering a solution, please let me know in the comments.
Yes I found the solution,
Thanks ppittle, your link to Kev's answer helped. I tried the suggestion in the answer but it didn't work in my scenario. However, the link posted by Kev in the answer helped alot. What worked was the setting in the applicationHost.config in your production server [where IIS is].
Look for a file called applicationHost.config at this location:
C:\Windows\System32\inetsrv\config
Change the "overrideModeDefault" setting below from Deny to Allow.
This is what worked for me. Thanks StackOverflow!
I had this same issue, but didn't see this answer anywhere:
The user my application was running under didn't have permission to access the database that was configured in the web.config. There was no indication that this was the problem that I could find.
The way I found this was by deploying in DEBUG instead of Release, which then showed me the error message.

Searching on 404 page returns back to 404 page back

We have a 404 page. When we are in 404 page, we have search box. if we try to search from search box, it again returns to 404 page. How could we handle this?
PS: My search button is inside user control and user control is inside masterpage.
When we go to the site below;
http://www.x.com/dk
it goes to 404.
then if we make search from th,s 404 page it directs us to the link below;
http://www.x.com/dk?404%3bhttp%3a%2f%2fwww.x.com%3a80%2fdk
my web config sets
<customErrors mode="Off" defaultRedirect="Error.aspx">
<error statusCode="404" redirect="PageNotFound.aspx" />
</customErrors>
<httpErrors>
<remove statusCode="404" subStatusCode="-1" />
<error statusCode="404" path="/PageNotFound.aspx" prefixLanguageFilePath="" responseMode="ExecuteURL" />
</httpErrors>
I solved this problem via javascript
<script type="text/javascript">
$("#btnSearch").attr("onclick", "Search('/Search.aspx?text=' + encodeURI($('#txtSearchInput').val())); return false;");
function Search(text) {
location.href = text;
}
</script>

MVC custom error pages work in dev but not in production

I have created some custom error pages in a MVC4 project. I use Application_Error and also the HandleErrorAttribute for routing.
Also,
It works fine in my dev computer, under IIS 8.0
When I publish the project to the production server, under IIS 7.5, it shows the default error pages, not custom pages.
What am I missing?
<customErrors mode="On" defaultRedirect="~/Error/Error.html" redirectMode="ResponseRewrite">
<error redirect="~/Error/403.aspx" statusCode="403" />
<error redirect="~/Error/404.aspx" statusCode="404" />
<error redirect="~/Error/500.html" statusCode="500" />
</customErrors>
Create page 403.aspx in root directory "Error"
<%# Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %>
<!DOCTYPE html>
<html>
<head runat="server">
<meta name="viewport" content="width=device-width" />
<title>403 Not Found</title>
</head>
<body>
<%
Server.ClearError();
Response.Status = "403 - Forbidden: Access is denied.";
Response.StatusCode = 403;
%>
<div>
<h2>403 - Forbidden: Access is denied.</h2>
</div>
</body>
</html>
Remove any response code setting statement from the action method.
Like
Response.StatusCode = 404;
Remove it and give a try.

Resources