ASP.NET MVC 404 Error Handling [duplicate] - asp.net-mvc

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How can I properly handle 404 in ASP.NET MVC?
I've made the changes outlined at 404 Http error handler in Asp.Net MVC (RC 5) and I'm still getting the standard 404 error page. Do I need to change something in IIS?

I've investigated A LOT on how to properly manage 404s in MVC (specifically MVC3), and this, IMHO is the best solution I've come up with:
In global.asax:
public class MvcApplication : HttpApplication
{
protected void Application_EndRequest()
{
if (Context.Response.StatusCode == 404)
{
Response.Clear();
var rd = new RouteData();
rd.DataTokens["area"] = "AreaName"; // In case controller is in another area
rd.Values["controller"] = "Errors";
rd.Values["action"] = "NotFound";
IController c = new ErrorsController();
c.Execute(new RequestContext(new HttpContextWrapper(Context), rd));
}
}
}
ErrorsController:
public sealed class ErrorsController : Controller
{
public ActionResult NotFound()
{
ActionResult result;
object model = Request.Url.PathAndQuery;
if (!Request.IsAjaxRequest())
result = View(model);
else
result = PartialView("_NotFound", model);
return result;
}
}
Edit:
If you're using IoC (e.g. AutoFac), you should create your controller using:
var rc = new RequestContext(new HttpContextWrapper(Context), rd);
var c = ControllerBuilder.Current.GetControllerFactory().CreateController(rc, "Errors");
c.Execute(rc);
Instead of
IController c = new ErrorsController();
c.Execute(new RequestContext(new HttpContextWrapper(Context), rd));
(Optional)
Explanation:
There are 6 scenarios that I can think of where an ASP.NET MVC3 apps can generate 404s.
Generated by ASP.NET:
Scenario 1: URL does not match a route in the route table.
Generated by ASP.NET MVC:
Scenario 2: URL matches a route, but specifies a controller that doesn't exist.
Scenario 3: URL matches a route, but specifies an action that doesn't exist.
Manually generated:
Scenario 4: An action returns an HttpNotFoundResult by using the method HttpNotFound().
Scenario 5: An action throws an HttpException with the status code 404.
Scenario 6: An actions manually modifies the Response.StatusCode property to 404.
Objectives
(A) Show a custom 404 error page to the user.
(B) Maintain the 404 status code on the client response (specially important for SEO).
(C) Send the response directly, without involving a 302 redirection.
Solution Attempt: Custom Errors
<system.web>
<customErrors mode="On">
<error statusCode="404" redirect="~/Errors/NotFound"/>
</customErrors>
</system.web>
Problems with this solution:
Does not comply with objective (A) in scenarios (1), (4), (6).
Does not comply with objective (B) automatically. It must be programmed manually.
Does not comply with objective (C).
Solution Attempt: HTTP Errors
<system.webServer>
<httpErrors errorMode="Custom">
<remove statusCode="404"/>
<error statusCode="404" path="App/Errors/NotFound" responseMode="ExecuteURL"/>
</httpErrors>
</system.webServer>
Problems with this solution:
Only works on IIS 7+.
Does not comply with objective (A) in scenarios (2), (3), (5).
Does not comply with objective (B) automatically. It must be programmed manually.
Solution Attempt: HTTP Errors with Replace
<system.webServer>
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="404"/>
<error statusCode="404" path="App/Errors/NotFound" responseMode="ExecuteURL"/>
</httpErrors>
</system.webServer>
Problems with this solution:
Only works on IIS 7+.
Does not comply with objective (B) automatically. It must be programmed manually.
It obscures application level http exceptions. E.g. can't use customErrors section, System.Web.Mvc.HandleErrorAttribute, etc. It can't only show generic error pages.
Solution Attempt customErrors and HTTP Errors
<system.web>
<customErrors mode="On">
<error statusCode="404" redirect="~/Errors/NotFound"/>
</customError>
</system.web>
and
<system.webServer>
<httpErrors errorMode="Custom">
<remove statusCode="404"/>
<error statusCode="404" path="App/Errors/NotFound" responseMode="ExecuteURL"/>
</httpErrors>
</system.webServer>
Problems with this solution:
Only works on IIS 7+.
Does not comply with objective (B) automatically. It must be programmed manually.
Does not comply with objective (C) in scenarios (2), (3), (5).
People that have troubled with this before even tried to create their own libraries (see http://aboutcode.net/2011/02/26/handling-not-found-with-asp-net-mvc3.html). But the previous solution seems to cover all the scenarios without the complexity of using an external library.

Yet another solution.
Add ErrorControllers or static page to with 404 error information.
Modify your web.config (in case of controller).
<system.web>
<customErrors mode="On" >
<error statusCode="404" redirect="~/Errors/Error404" />
</customErrors>
</system.web>
Or in case of static page
<system.web>
<customErrors mode="On" >
<error statusCode="404" redirect="~/Static404.html" />
</customErrors>
</system.web>
This will handle both missed routes and missed actions.

The response from Marco is the BEST solution. I needed to control my error handling, and I mean really CONTROL it. Of course, I have extended the solution a little and created a full error management system that manages everything. I have also read about this solution in other blogs and it seems very acceptable by most of the advanced developers.
Here is the final code that I am using:
protected void Application_EndRequest()
{
if (Context.Response.StatusCode == 404)
{
var exception = Server.GetLastError();
var httpException = exception as HttpException;
Response.Clear();
Server.ClearError();
var routeData = new RouteData();
routeData.Values["controller"] = "ErrorManager";
routeData.Values["action"] = "Fire404Error";
routeData.Values["exception"] = exception;
Response.StatusCode = 500;
if (httpException != null)
{
Response.StatusCode = httpException.GetHttpCode();
switch (Response.StatusCode)
{
case 404:
routeData.Values["action"] = "Fire404Error";
break;
}
}
// Avoid IIS7 getting in the middle
Response.TrySkipIisCustomErrors = true;
IController errormanagerController = new ErrorManagerController();
HttpContextWrapper wrapper = new HttpContextWrapper(Context);
var rc = new RequestContext(wrapper, routeData);
errormanagerController.Execute(rc);
}
}
and inside my ErrorManagerController :
public void Fire404Error(HttpException exception)
{
//you can place any other error handling code here
throw new PageNotFoundException("page or resource");
}
Now, in my Action, I am throwing a Custom Exception that I have created. And my Controller is inheriting from a custom Controller Based class that I have created. The Custom Base Controller was created to override error handling. Here is my custom Base Controller class:
public class MyBasePageController : Controller
{
protected override void OnException(ExceptionContext filterContext)
{
filterContext.GetType();
filterContext.ExceptionHandled = true;
this.View("ErrorManager", filterContext).ExecuteResult(this.ControllerContext);
base.OnException(filterContext);
}
}
The "ErrorManager" in the above code is just a view that is using a Model based on ExceptionContext
My solution works perfectly and I am able to handle ANY error on my website and display different messages based on ANY exception type.

Looks like this is the best way to catch everything.
How can I properly handle 404 in ASP.NET MVC?

In IIS, you can specify a redirect to "certain" page based on error code. In you example, you can configure 404 - > Your customized 404 error page.

What I can recomend is to look on FilterAttribute. For example MVC already has HandleErrorAttribute. You can customize it to handle only 404. Reply if you are interesed I will look example.
BTW
Solution(with last route) that you have accepted in previous question does not work in much of the situations. Second solution with HandleUnknownAction will work but require to make this change in each controller or to have single base controller.
My choice is a solution with HandleUnknownAction.

Related

Can an ASP.NET MVC Area display its own set of error pages?

I've been consolidating some of my web apps into one main ASP.NET MVC project; assigning some of them to separate Areas, so that they can be accessed via subdomains.
Using this (quite helpful) resource (https://dusted.codes/demystifying-aspnet-mvc-5-error-pages-and-error-logging), I've set up customErrors and httpErrors in the Web.config, so that custom error pages are displayed. Works well.
I'll use different layout/styling per Area/subdomain, so I'm wondering:
How can I get an Area to display its own set of error pages?
With the current setup, all the subdomains will display the main set of custom errors that are added to the customErrors and httpErrors sections (403.html, 404.html, et cetera); but I'd prefer tailored error pages for some subdomains. (If one of the areas is exclusively handled by a separate domain altogether, for example, it won't be practical to serve the regular error pages.)
Update:
Here is the scenario, with code, as requested. Thanks to Ben Foster, who offered good guidance here: http://benfoster.io/blog/aspnet-mvc-custom-error-pages2. I've put the code for customErrors, but not the corresponding httpErrors... left it out for brevity.
<system.web>
<customErrors mode="On" redirectMode="ResponseRewrite" defaultRedirect="~/500.aspx">
<error statusCode="404" redirect="~/404.aspx" />
<error statusCode="500" redirect="~/500.aspx" />
</customErrors>
</system.web>
<location path="MyArea1">
<system.web>
<customErrors mode="On" redirectMode="ResponseRewrite" defaultRedirect="~/Areas/MyArea1/500.aspx">
<error statusCode="404" redirect="~/Areas/MyArea1/404.aspx" />
<error statusCode="500" redirect="~/Areas/MyArea1/500.aspx" />
</customErrors>
</system.web>
</location>
<location path="MyArea2">
<system.web>
<customErrors mode="On" redirectMode="ResponseRewrite" defaultRedirect="~/Areas/MyArea2/500.aspx">
<error statusCode="404" redirect="~/Areas/MyArea2/404.aspx" />
<error statusCode="500" redirect="~/Areas/MyArea2/500.aspx" />
</customErrors>
</system.web>
</location>
The above code works well:
If I navigate to "example.com/does/not/exist", I get the
expected error page at ~/404.aspx.
If I navigate to "example.com/MyArea1/does/not/exist", I will
get the custom error page at ~/Areas/MyArea1/404.aspx.
The challenge:
Now I'd like an Area (MyArea2) to be served by a totally separate domain (e.g. exampleOnMyOtherDomain.com), using HostDomainConstraint (as recommended by #TetsuyaYamamoto, in a comment below). A link that would have been accessible via "example.com/MyArea2/validlink" will now be accessed this way: "exampleOnMyOtherDomain.com/validlink".
Now, if I try "exampleOnMyOtherDomain.com/does/not/exist", I'll be served the top-level 404 (~/404.aspx). This is probably because "MyArea2" is not in the path anymore, so the location with the path "MyArea2" will not be picked up.
How can I get the Area (MyArea2) to serve its own error pages?
Based on some research, and helpful pointers from #TetsuyaYamamoto, I've employed the strategy below.
I'm handling the "Application_Error" event in Global.asax, using the following code:
protected void Application_Error(object sender, EventArgs e)
{
string hostName = Request.Headers["host"].Split(':')[0];
if (hostName.Contains("exampleOnMyOtherDomain"))
{
Exception exception = Server.GetLastError();
Response.Clear();
HttpException httpException = exception as HttpException;
Response.TrySkipIisCustomErrors = true;
switch (httpException.GetHttpCode())
{
case 404:
Response.StatusCode = 404;
Server.Transfer("~/Errors/MyArea2_404.htm");
break;
case 500:
default:
Response.StatusCode = 500;
Server.Transfer("~/Errors/MyArea2_500.htm");
break;
}
Server.ClearError();
}
}
Points to note:
hostName.Contains("exampleOnMyOtherDomain") should compare the Host name with the Area I'm interested in handling. I'll add else...if statements for other Areas;
Response.TrySkipIisCustomErrors = true should prevent IIS from attempting to handle the error;
Response.StatusCode sets the status code appropriately ('404', '500'...);
Server.Transfer() reads in a file that I'd like to display as the error page;
Server.ClearError() should signal that the error has already been handled.
I want customErrors/httpErrors to continue handling regular errors. When execution passes through the Application_Error block without being handled (i.e. Server.ClearError() isn't called), customErrors/httpErrors will handle the error.
It seems that this is a decent strategy for handling errors for Areas that are served by a different domain.

Custom error pages in IIS

I have the following set-up in my web.config
<customErrors mode="RemoteOnly" defaultRedirect="/ServerError" redirectMode="ResponseRewrite"/>
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="400" subStatusCode="-1" />
<remove statusCode="404" subStatusCode="-1" />
<remove statusCode="500" subStatusCode="-1" />
<error statusCode="400" path="/error/Error400" responseMode="ExecuteURL" />
<error statusCode="404" path="/error/Error404" responseMode="ExecuteURL" />
<error statusCode="500" path="/error/Error500" responseMode="ExecuteURL" />
</httpErrors>
With the above configuration, our website is able to catch 404s, and display the nice 404 page served from /error/error404 with the 404 Header.
Now i have the following scenario:
1. User navigates to /action/id
2. Id is not found, i would like to return a 404, but serve a custom 404, different from the generic one served from /error/error404. i.e. serve a different custom page;
In my controller i have the following:
Response.StatusCode=(int)HttpStatusCode.NotFound;
Response.TrySkipIisCustomErrors = true;
return View("SomeView", model);
Is this something that can be achieved ?
PS: using IIS 8
LE In case anyone is interested in the solution i implemented, i have done the following:
1. In my action, i set a session variable Session["InvalidId"]=something
2. In my ErrorController i have the following:
var invalidId = Session["InvalidId"];
if(invalidId != null)
{
return View("SomeView", model);
}
This helped me serve a different 404 page to my generic one.
Thanks for the help !
Yes, this can be easily achieved and you do not really need other pages. You need to have some session variables for custom messages and use them to determine whether you need to display some messages. If so, then display them in your view.
Algorithm:
Your custom page detects an error
Some error messages are generated
Your custom page redirects to the error page
The error page checks for error messages to be displayed
If there are such error messages, then they are displayed and the error message queue is cleared
Depending on how you handle your exceptions, you could create your own exception class that inherits from HttpException.
[Serializable]
public class MyHttpException : HttpException
{
// Constructors ...
// You could either allow for an http status code to be passed in a
// constructor (to make your class more reusable) or you could call the
// base constructor with 404
// Additional properties if needed ...
}
Then, in you action, when your condition is met (i.e. id not found) you can throw a new MyHttpException.
Your exception handling mechanism can test to see if the current exception is a MyHttpException and react to that with a custom view. It should also set the correct response status code, like you were doing.
The status code can come from MyHttpException since it is a HttpException:
(HttpStatusCode)myHttpException.GetHttpCode()
I'm not sure what controllers you have or how you capture application-wide exceptions but what I have is an ErrorController with an Index action that takes an Exception as a parameter:
public ActionResult Index(Exception exception) { ... }
It is this action that decides what gets returned based on the exception object, similar to what I described above.
Hope this helps.
P.S. I have a similar <httpErrors>...</httpErrors> setup in my web.config and my custom exception works with a 404 status code as described above.

Which HTTP Status Codes to cover for MVC error handling

I'm currently developing custom error pages in my error handling code for my MVC application. But I'm unclear as to which HTTP status codes I'm meant to cover.
Question: is there a typical list of HTTP status codes that should be catered for?
Alot articles which explain how to do MVC error handling and custom error pages but appear to only show several of the HTTP Status Codes: 403, 404, and 500 in their error handling code. What about HTTP Status Code: 408 as an example? Should this be covered? What about the tonne of other status codes - HTTP status codes on wiki
This may sound like a dumb question, but I really don't know the answer and can't find an information on this. Am I missing something here, i.e. should only a subset of status codes be covered?
If it helps, below is what I've done for my MVC error handling. This code (so far with the little testing that I've done) covers 404, and all 50x type exceptions:
1 In web.config, and entry for each HTTP status code I want to cover
<httpErrors errorMode="Custom" existingResponse="Replace" >
<remove statusCode="403" />
<remove statusCode="404" />
<remove statusCode="500" />
<error statusCode="403" responseMode="ExecuteURL" path="/Error/Forbidden" />
<error statusCode="404" responseMode="ExecuteURL" path="/Error/NotFound" />
<error statusCode="500" responseMode="ExecuteURL" path="/Error" />
</httpErrors>
2 An error controller
namespace MyApp.Controllers
{
public class ErrorController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult Forbidden()
{
return View();
}
public ActionResult NotFound()
{
return View();
}
3 User friendly error pages:
/Views/Shared/Index.cshtml
/Views/Shared/Forbidden.cshtml
/Views/Shared/NotFound.cshtml
4 ELMAH for logging
Further findings at 2 Nov 2015
Something I've just discovered that has been staring me in the face which I've missed... In IIS, the default Error pages covered are:
401 – Unauthorized
403 – Forbidden
404 – Not Found
405 – Method Not Allowed
406 – Not Acceptable
412 – Precondition Failed
500 – Internal Server Error
501 – Not Implemented
502 – Bad Gateway
If this is good range Microsoft have set, then I will go by this as a guide going forwards!
There may be another way: this solution uses 1 custom-error page to handle all types (I think?)
[1]: Remove all 'customErrors' & 'httpErrors' from Web.config
[2]: Check 'App_Start/FilterConfig.cs' looks like this:
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
}
[3]: in 'Global.asax' add this method:
public void Application_Error(Object sender, EventArgs e)
{
Exception exception = Server.GetLastError();
Server.ClearError();
var routeData = new RouteData();
routeData.Values.Add("controller", "ErrorPage");
routeData.Values.Add("action", "Error");
routeData.Values.Add("exception", exception);
if (exception.GetType() == typeof(HttpException))
{
routeData.Values.Add("statusCode", ((HttpException)exception).GetHttpCode());
}
else
{
routeData.Values.Add("statusCode", 500);
}
Response.TrySkipIisCustomErrors = true;
IController controller = new ErrorPageController();
controller.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
Response.End();
}
[4]: Add 'Controllers/ErrorPageController.cs'
public class ErrorPageController : Controller
{
public ActionResult Error(int statusCode, Exception exception)
{
Response.StatusCode = statusCode;
ViewBag.StatusCode = statusCode + " Error";
return View();
}
}
[5]: in 'Views/Shared/Error.cshtml'
#model System.Web.Mvc.HandleErrorInfo
#{
ViewBag.Title = (!String.IsNullOrEmpty(ViewBag.StatusCode)) ? ViewBag.StatusCode : "500 Error";
}
<h1 class="error">#(!String.IsNullOrEmpty(ViewBag.StatusCode) ? ViewBag.StatusCode : "500 Error"):</h1>
//#Model.ActionName
//#Model.ContollerName
//#Model.Exception.Message
//#Model.Exception.StackTrace
An interesting question, IMHO.
These three errors (403, 404 and 500) are the most common errors that can happen to the real user accessing your site with a standard browser.
On other hand, the HTTP standard was written for both server and agent developers in order to define how both sides should operate. Naturally, the standard browsers like IE, Chrome, Firefox, etc. as well as the standard robots like Google or Bing bots correctly fulfill the requirements, but some proprietary written agent may send a malformed request, and the standard provides the set of codes the server should send in this situation. For example, if the Content-Length field is missed the server returns the error code 411. However, you shouldn't provide user-friendly pages for such a situation.
The code 408 (Request timeout) is explained in the standard as following:
"The client did not produce a request within the time that the server was prepared to wait. The client MAY repeat the request without modifications at any later time."
and it also not a case you should make user-friendly page for.
To make a long story short, don't worry :)
I'm trying to find out the answer also. My code looks scarily like yours. This is a great question with so few views, I've set a bounty on this question. I myself have handled the following codes so far:
<system.webServer>
<!-- Custom error pages -->
<httpErrors errorMode="Custom" existingResponse="Replace">
<!-- Redirect IIS 400 Bad Request responses to the error controllers bad request action. -->
<remove statusCode="400" />
<error statusCode="400" responseMode="ExecuteURL" path="/error/badrequest" />
<!-- Redirect IIS 401 Unauthorized responses to the error controllers unauthorized action. -->
<remove statusCode="401" />
<error statusCode="401" responseMode="ExecuteURL" path="/error/unauthorized" />
<!-- Redirect IIS 403.14 Forbidden responses to the error controllers not found action.
A 403.14 happens when navigating to an empty folder like /Content and directory browsing is turned off
See http://rehansaeed.co.uk/securing-the-aspnet-mvc-web-config/ and http://www.troyhunt.com/2014/09/solving-tyranny-of-http-403-responses.html -->
<error statusCode="403" subStatusCode="14" responseMode="ExecuteURL" path="/error/notfound" />
<!-- Redirect IIS 404 Not Found responses to the error controllers not found action. -->
<remove statusCode="404" />
<error statusCode="404" responseMode="ExecuteURL" path="/error/notfound" />
<!-- Redirect IIS 500 Internal Server Error responses to the error controllers internal server error action. -->
<remove statusCode="500" />
<error statusCode="500" responseMode="ExecuteURL" path="/error" />
</httpErrors>
</system.webServer>
My reasoning is as follows:
400 - Controllers have the BadRequest() method built in and you may want to return this when a parameter passed to the action is invalid.
401 - Applying the Authorize attribute to a controller or action causes a 401 Unauthorized response. Controllers also have the Unauthorized() method built in.
403.14 - Redirect these to 404 Not Found responses as a Forbidden is just plain wrong (See Securing your web.config and Troy Hunt's blog for more information).
404 - Thrown when the user browses to a page not found.
500 - Thrown when something goes catastrophically wrong.
Overall I feel you should handle those codes that you yourself are going to use. The problem is that IIS does all kinds of strange things and we need to handle some of it's incorrect or invalid responses such as the 403.14 I listed above.
Here is a complete list of IIS HTTP Status Codes and Sub-Status Codes which might be useful to our cause. I have a feeling the 403 Forbidden response should also be supported as it seems to be a fairly prominent response thrown by IIS.
One interesting thing I discovered while Googling is that navigating to:
yoursite/<script></script>
Returns a 500 Internal Server from IIS. I feel this should return a 404. The IIS error page does not tell us what the Sub-Status Code is and I would be interested to know how we can find out, so that we can redirect the 500.Something to a 404 Not Found page.
Here is a link to the GitHub page for the ASP.NET MVC Boilerplate project, for which I am doing this research and where you can look at my code.
Don't rely too much on http status codes.
I have worked with a few bad web developers over the last couple of years that have incorrectly used them in their responses.
I may look for codes within 200-299 for an indication of success.
I may look for codes >500 to indicate a server failure.
Beyond that, I use a selfish approach i.e. if you are making a request that your are expecting to have a package of data returned to you, then inspect the data. If there is no data or if the data is bad then I know for certain that there was a problem, because I didn't get what I needed to continue running my application in a nominal way.

Custom Error redirection does not work in ASP.NET MVC Web.Config

In my application I have included <customerror> tag in Web.config as follows:
<customErrors mode="On">
<error statusCode="404" redirect="/Error/404"/>
<error statusCode="403" redirect="/Error/403"/>
<error statusCode="500" redirect="/Error/500"/>
</customErrors>
I have created an entry in my route config such that any request with url pattern /Error/{status} goes to a specific controller action with status as a parameter.
And I have a custom ActionFilterAttribute which checks whether the user is admin and returns an HTTP 403 result if not. Following is my custom filter attribute.
public class RequireAdminAttribute: ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (!UserOperations.IsAdmin())
{
filterContext.Result = new Http403Result();
}
}
}
internal class Http403Result : ActionResult
{
public override void ExecuteResult(ControllerContext context)
{
// Set the response code to 403.
context.HttpContext.Response.StatusCode = 403;
}
}
Now, what I need is user to be redirect to the /Error/403 page if he is not authorized. When I run my application, my applition does not redirect to the error page when 403 error occurs. If a 404 error occurs, it redirects to the given 404 error page (in most cases when 404 occurs). What is the reason for this? Can anybody give me a solution? Do I need to hardcode redirection to error page using something like RedirectToRouteResult?
Edit:
In some cases redirection does not work where I explicitely used return HttpNotFound(); result as well. I would like to know whether using return HttpNotFound(); does not redirect to a custom page.
Thank you.
Try to add this to your Web.config:
<system.webServer>
<httpErrors existingResponse="Replace" errorMode="Custom" defaultResponseMode="Redirect">
<remove statusCode="403"/>
<error responseMode="ExecuteURL" statusCode="403" path="/Error/403" />
</httpErrors>
</system.webServer>

Throwing a 404 like StackOverflow's, without redirect, when using IOCControllerFactory

I found another question posted on here which provided a solution to the first part of my question, i.e. how to generate a 404 page in ASP.NET MVC WITHOUT redirecting to another page (so the originally requested url remains in the address bar).
ASP.NET MVC - How to throw a 404 page similar to that on StackOverflow
protected void Application_Error(object sender, EventArgs e)
{
var exception = Server.GetLastError();
Response.Clear();
var httpException = exception as HttpException;
var routeData = new RouteData();
routeData.Values.Add("controller", "Error");
if (httpException != null)
{
routeData.Values.Add("action", httpException.GetHttpCode() == 404 ? "NotFound" : "Unknown");
// clear the error, otherwise, we will always get the default error page.
Server.ClearError();
// call the controller with the route
IController errorController = new ErrorController();
errorController.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
}
}
The 404 side of things works fine for me if I don't use an IOCControllerFactory, but as soon as I do use a factory, the error code in global.asax isn't used and instead I get the following error:
The IControllerFactory 'MyNamespace.IOCControllerFactory' did not
return a controller for the name 'blah'.
How do I get around this, without resorting to getting rid of my controllerfactory, and creating a parameterless constructor for each of my controllers?
ASP.NET can do this OOTB (starting from 3.5).
On the <CustomErrors> element add: redirectMode=ResponseRewrite
Update
I posted the wrong code. It is IIS 7 which handles this.
<system.webServer>
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="404" />
<error statusCode="404" path="/home/notfound" responseMode="ExecuteURL" />
</httpErrors>
<system.webServer>

Resources