Solution:
The problem, it turned out, was the use of the master page. I got it to work by setting the status code later in the pages lifecycle, obviously the rendering of the master page was resetting it, so I overrode the render method and set it after the render was complete.
protected override void Render(HtmlTextWriter writer)
{
base.Render(writer);
Response.StatusCode = 404;
}
More work could be done to find out exactly when the master page is setting the status, but I'll leave that to you.
Original Post:
I was able to get a test web app to work fine, well it at least displayed the custom error page and returned a 404 status code. I can't tell you what is wrong with your app, but I can tell you what I did:
1) Edited the web.config for custom errors:
<customErrors mode="On">
<error statusCode="404" redirect="404.aspx"/>
</customErrors>
2) Added a 404.aspx page and set the status code to 404.
public partial class _04 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Response.StatusCode = 404;
}
}
Thats about it, if I go to any page extension that is processed by Asp.Net and does not exist, my fiddler log clearly shows a 404, here is the header:
HTTP/1.1 404 Not Found
Server: Microsoft-IIS/5.1
Date: Sun, 07 Dec 2008 06:04:13 GMT
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50727
Cache-Control: private
Content-Type: text/html; charset=utf-8
Content-Length: 533
Now if I go to a page that is not processed by Asp.Net, like a htm file, the custom page does not show and the 404 that is configured by IIS is displayed.
Here is a post that goes into some more details that may be of use to you and your problem, my test does do a redirect to the new page so the url of the requested file is pretty much lost (except its in the query string).
Google 404 and .NET Custom Error Pages
Header Spy Response:
HTTP/1.1 404 Not Found
Date: Sun, 07 Dec 2008 06:21:20 GMT
In the RTM version of ASP.NET MVC, the Cancel property is missing. This code works with ASP.NET MVC RTM:
using System;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Resources;
namespace ePegasus.Web.ActionFilters
{
public class CustomAuthorize : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
if (filterContext.Result is HttpUnauthorizedResult)
{
filterContext.Result = new RedirectToRouteResult(
new System.Web.Routing.RouteValueDictionary
{
{ "langCode", filterContext.RouteData.Values[ "langCode" ] },
{ "controller", "Account" },
{ "action", "Login" },
{ "ReturnUrl", filterContext.HttpContext.Request.RawUrl }
});
}
}
}
}
Edit: You may want to disable the default forms authentication loginUrl in web.config - in case somebody forgets you have a custom attribute and uses the built in [Authorize] attribute by mistake.
Modify the value in web.config:
<forms loginUrl="~/Account/ERROR" timeout="2880" />
Then make an action method 'ERROR' that logs an error and redirects the user to the most generic login page you have.
Best Answer
If you want to do it from global.asax, try something like the following