jdehlin
jdehlin

Reputation: 11451

Custom routes with custom 404 page in MVC

I have a custom route set up:

var tradeCategoriesRoute = routes.MapRoute(
     name: "TradeCategoriesIndex",
     url: "TradeCategories/{*categories}",
     defaults:
          new
          {
                controller = "TradeCategories",
                action = "Index"
          },
          namespaces: new[] {"Website.Controllers"}
);
tradeCategoriesRoute.DataTokens["UseNamespaceFallback"] = false;
tradeCategoriesRoute.RouteHandler = new CategoriesRouteHandler();

I also have a custom 404 page set up in my Global.asax:

private void Application_Error(object sender, EventArgs e)
{
    var exception = Server.GetLastError();
    var httpException = exception as HttpException;
    DisplayErrorPage(httpException);
}

private void DisplayErrorPage(HttpException httpException)
{
    Response.Clear();
    var routeData = new RouteData();

    if (httpException != null && httpException.GetHttpCode() == 404)
    {
        routeData.Values.Add("controller", "Error");
        routeData.Values.Add("action", "Missing");
    }
    else if (httpException != null && httpException.GetHttpCode() == 500)
    {
        routeData.Values.Add("controller", "Error");
        routeData.Values.Add("action", "Index");
        routeData.Values.Add("status", httpException.GetHttpCode());
    }
    else
    {
        routeData.Values.Add("controller", "Error");
        routeData.Values.Add("action", "Index");
        routeData.Values.Add("status", 500);
    }
    routeData.Values.Add("error", httpException);
    Server.ClearError();
    Response.TrySkipIisCustomErrors = true;
    IController errorController = ObjectFactory.GetInstance<ErrorController>();
    errorController.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
    Response.End();
}

It seems that my real problem is the custom route handler that I made:

public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
    IRouteHandler handler = new MvcRouteHandler();
    var values = requestContext.RouteData.Values;
    if (values["categories"] != null)
        values["categoryNames"] = values["categories"].ToString().Split('/').Where(x => !string.IsNullOrWhiteSpace(x)).ToArray();
    else
        values["categoryNames"] = new string[0];
    return handler.GetHttpHandler(requestContext);
}

It works fine and properly displays the 404 page for routes like "/doesnotexist" but doesn't work for routes like "/TradeCategories/doesnotexist". Instead I get a built in 404 page with the message "The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.".

How can I get my custom 404 page working with these custom routes?

Upvotes: 1

Views: 284

Answers (2)

psantiago
psantiago

Reputation: 714

Something you might want to look into is your implementation for the TradeCategories Controller's Index action. The custom route and custom handler look like they'll match basically any route (TradeCategories/*), so I'm guessing something in your action or view is returning a 404 without throwing an exception that can be caught in global.asax?

Upvotes: 1

Cacho Santa
Cacho Santa

Reputation: 6914

You need to override the Application_Error method in you GLobal.asax

From the link:

void Application_Error(object sender, EventArgs e)
{
  // Code that runs when an unhandled error occurs

  // Get the exception object.
  Exception exc = Server.GetLastError();

  // Handle HTTP errors
  if (exc.GetType() == typeof(HttpException))
  {
    // The Complete Error Handling Example generates
    // some errors using URLs with "NoCatch" in them;
    // ignore these here to simulate what would happen
    // if a global.asax handler were not implemented.
      if (exc.Message.Contains("NoCatch") || exc.Message.Contains("maxUrlLength"))
      return;

    //Redirect HTTP errors to HttpError page
    Server.Transfer("HttpErrorPage.aspx");
  }

  // For other kinds of errors give the user some information
  // but stay on the default page
  Response.Write("<h2>Global Page Error</h2>\n");
  Response.Write(
      "<p>" + exc.Message + "</p>\n");
  Response.Write("Return to the <a href='Default.aspx'>" +
      "Default Page</a>\n");

  // Log the exception and notify system operators
  ExceptionUtility.LogException(exc, "DefaultPage");
  ExceptionUtility.NotifySystemOps(exc);

  // Clear the error from the server
  Server.ClearError();
}

This should work. However, I would rather redirect to a different page, instead of writing to the Response.

Something like this:

IController controller = new ErrorPageController();
    controller.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
    Response.End();

Upvotes: 0

Related Questions