I'm trying to build my tutorial project with routing. My main objective is to build two routes which won't generate 404 error in any case. By this I mean that if the path is wrong I want routing to use /Home/Index path. I have two following routes -
routes.MapRoute("Default", "{controller}/{action}",
new {controller = "Home", action = "Index"}
);
routes.MapRoute("Second", "{*catchall}",
new {controller = "Home", action = "Index", id = UrlParameter.Optional}
);
It works fine when I use nonexistent path which doesn't matches the first route, like this -
But if it does, then I have the following -
or
I understand the reason why it happens. However at the present moment, I only managed to find 'some sort' of a solution. Adding the following code to web.config file -
<customErrors mode="On">
<error statusCode="404" redirect="~/Home/Index"/>
</customErrors>
However, I don't think that it is the best way to solve this problem. Because, as far as I can understand, it simply catches all errors and redirects it to the correct path, without actually using routing. So I don't think I need this global handling.
So could somebody please give me a hint or provide me with a good solution to my problem. Thank you.
Well, you didn't really define what "wrong" routing is, so here is my definition:
I used constraints to do this. AFAIK, it is not possible to use a constraint on an optional parameter. This means that in order to make the id
parameter optional, you need 3 routes.
routes.MapRoute(
name: "DefaultWithID",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index" },
constraints: new { action = new ActionExistsConstraint(), id = new ParameterExistsConstraint() }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}",
defaults: new { controller = "Home", action = "Index" },
constraints: new { action = new ActionExistsConstraint() }
);
routes.MapRoute(
name: "Second",
url: "{*catchall}",
defaults: new { controller = "Home", action = "Index" }
);
public class ActionExistsConstraint : IRouteConstraint
{
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
if (routeDirection == RouteDirection.IncomingRequest)
{
var action = values["action"] as string;
var controller = values["controller"] as string;
var thisAssembly = this.GetType().Assembly;
Type[] types = thisAssembly.GetTypes();
Type type = types.Where(t => t.Name == (controller + "Controller")).SingleOrDefault();
// Ensure the action method exists
return type != null && type.GetMethod(action) != null;
}
return true;
}
}
public class ParameterExistsConstraint : IRouteConstraint
{
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
if (routeDirection == RouteDirection.IncomingRequest)
{
var action = values["action"] as string;
var controller = values["controller"] as string;
var thisAssembly = this.GetType().Assembly;
Type[] types = thisAssembly.GetTypes();
Type type = types.Where(t => t.Name == (controller + "Controller")).SingleOrDefault();
var method = type.GetMethod(action);
if (type != null && method != null)
{
// Ensure the parameter exists on the action method
var param = method.GetParameters().Where(p => p.Name == parameterName).FirstOrDefault();
return param != null;
}
return false;
}
return true;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With