2

I'm trying to properly handle and return a 404 for this URL: http://localhost:2867/dd./xml (notice the dot before the slash)

In my current implementation I get 4 exceptions/errors in Application_Error. The first exception returned by Server.GetLastError() is System.Web.HttpException while the next three are null.

I made a bare minimum implementation to reproduce this issue. Here's the code in global.asax.cs:

protected void Application_Error(object sender, EventArgs e)
{
  Exception exception = Server.GetLastError();
  Server.ClearError();

  var routeData = new RouteData();
  routeData.Values.Add("controller", "Error");
  routeData.Values.Add("action", "Generic");
  routeData.Values.Add("area", "");

  IController errorController = new ErrorController();
  // this line throws System.Web.HttpException is a view is returned from ErrorController
  errorController.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
}

The error controller looks like this:

public class ErrorController : Controller
{
  public ActionResult Generic()
  {
    Response.TrySkipIisCustomErrors = true;
    Response.StatusCode = (int)HttpStatusCode.NotFound;

    return View();
    // returning content rather than a View doesn't fire 'System.Web.HttpException' in Application_Error
    //return Content("Some error!");
  }
}

There are two issues. One is that for the given URL instead of one error in Application_Error I get 3 or 4, and the other is that when returning a view from the ErrorController an exception is thrown on the Execute call line in Application_Start. If a Content("something") is returned instead this internal (to MVC I assume) exception is not triggered.

In order to see the problem you have to be in debug mode and use the development server. When using IIS or IIS Express the error is not caught for some reason. Also, every now and then these errors go away. To get it back to the beginning you have to clean the solution.

If you'd like to play with it here's the bare minimum solution: http://dl.dropbox.com/u/16605600/InvalidUrl.zip

Thank you for your help!

pbz
  • 8,865
  • 14
  • 56
  • 70

2 Answers2

1

If you're using IIS7+ putting this in the web.config works:

<system.webServer>
  <httpErrors errorMode="Custom" existingResponse="Replace">
    <remove statusCode="404" />
    <error statusCode="404" responseMode="ExecuteURL" path="/Error/PageNotFound" />
  </httpErrors>
</system.webServer>

(Answer from How can I properly handle 404 in ASP.NET MVC?)

Would still be nice to know what is going on in the Application_Error.

Community
  • 1
  • 1
pbz
  • 8,865
  • 14
  • 56
  • 70
0

You can handle a 404 by changing the customeErrors section in the web.config
There is also a redirectMode attribute which you can use to control the nature of the error page redirection (and avoid the 302) (Read here)

<configuration>
  ...
  <system.web>
    <customErrors mode="RemoteOnly" 
                  redirectMode="ResponseRewrite" 
                  defaultRedirect="/ErrorPages/Oops.aspx">
      <error statusCode="404" redirect="/ErrorPages/404.aspx" />
    </customErrors>
...

http://www.asp.net/hosting/tutorials/displaying-a-custom-error-page-cs

In ASP.net MVC, there is a method you can override to catch all exceptions thrown in a controller. Just override Controller.OnException(...) and you can do custom error handling in there as well. If all of your controllers inherit from a common base controller class, you can put the error handling there.

http://msdn.microsoft.com/en-us/library/system.web.mvc.controller.onexception.aspx

TJB
  • 13,367
  • 4
  • 34
  • 46
  • If I'm not mistaken that works by redirecting to a different page which is not the proper way to return http errors. – pbz Nov 18 '11 at 18:37
  • Also, this code is used for other application errors, beside 404s. I focused on 404 just to show that something weird is going on. – pbz Nov 18 '11 at 18:39
  • @pbz The asp.net error handling will apply the proper error status code automatically, I'm not 100% clear on why its not proper to redirect to a different page (I'm a bit rusty on my http though...) Other errors can be handled with the 500 code, I'll also add details on the OnException controller method. – TJB Nov 18 '11 at 18:44
  • When a browser, or especially a search engine crawler, asks (GET) for http://example.com/somepage it expects an http code in the headers. If the URL is good then the returned code should be 200, if it doesn't exist it should return 404 or 410. If your page returns 302 (redirect to the 404 page for example) then the crawler would think the page has been moved rather than not found. – pbz Nov 18 '11 at 18:56
  • @pbz Ah, I haven't done much SEO related stuff, thanx for clarifying / sharing, I added info which appears to show how this is handled by a new 'redirectMode' attribute – TJB Nov 18 '11 at 19:59
  • These errors happen before a controller is executed, somewhere in the "which controller should handle this funky url" phase, so catching them in controller won't help. Thanks. – pbz Nov 18 '11 at 20:32
  • What about the 'redirectMode' attribute? that's independent of mvc/controllers – TJB Nov 18 '11 at 21:43
  • Thanks for your help! I believe the reason customErrors don't work is that MVC treats them differently; httpErrors seemed to have worked though. – pbz Nov 19 '11 at 02:36