0

I have two routes

routes.MapRoute(
    name: "Default",
    url: "{location}/{controller}/{action}/{id}",
    defaults: new { controller = "Products", action = "Index", id = UrlParameter.Optional }
    );

routes.MapRoute(
    name: "Home",
    url: "{controller}/{action}",
    defaults: new { controller = "Home", action = "Index" }
);

When user goes to main page, he has to chose two links:

<a href="/loc1/Products/index">Location 1</a>
<a href="/loc2/Products/index">Location 2</a>

Also I have ActionFilterAttribute, where I check for location parameter, and if url does not have it, i redirect users to main home page.

public override void OnActionExecuting(ActionExecutingContext filterContext)
{
    string location = (string)filterContext.RouteData.Values["location"];
    if (string.IsNullOrEmpty(location) 
        && filterContext.ActionDescriptor.ControllerDescriptor.ControllerName != "Home" 
        && !filterContext.IsChildAction)
    {
        filterContext.Result = new RedirectToRouteResult(
        new RouteValueDictionary 
        { 
            { "controller", "Home" }, 
            { "action", "Index" } 
        });
    }
        
    SessionUtils.SetLocationName(location);
}

Based on the location variable I will query different records from database, so when user does not provide any location in url, and tries to access Products/index/5 I want them to be redirected to the main page where they have to choose location and click one of the links. However I get error message:

The resource cannot be found.

Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.

Requested URL: /Products/index

How should I properly configure routes, so that users would be redirected to main page if there is no location parameter in url?

Community
  • 1
  • 1
Mantas Čekanauskas
  • 2,218
  • 6
  • 23
  • 43

4 Answers4

1

Your "Default" route, which includes the location is the only route which will ever be hit. The controller, action and id params are all optional, so a request for something like /Products/Index will actually be caught by the your "Default" route and the location param will be given "Products" and your controller param will be given "Index" as a value. The action param will be the default of "Index", and the id param will be disregarded. Since you obviously don't have an IndexController with an Index action, you get a 404.

To differentiate the routes, you need need to make your "Default" route require some kind of hard-coded prefix, i.e.

routes.MapRoute(
    name: "Default",
    url: "location/{location}/{controller}/{action}/{id}",
    defaults: new { controller = "Products", action = "Index", id = UrlParameter.Optional }
    );

Then, the /Products/Index route will fall through to your "Home" route and be interpreted properly as a route to ProductsController.Index. Alternatively, you can apply route contraints to the location param, so it doesn't match everything, i.e.:

routes.MapRoute(
    name: "Default",
    url: "{location}/{controller}/{action}/{id}",
    defaults: new { controller = "Products", action = "Index", id = UrlParameter.Optional },
    constraints: new { location = @"^(loc1|loc2)$" }
    );

Then, unless the first part of the URL matches either loc1 or loc2, it will fall through to the "Home" route.

Chris Pratt
  • 232,153
  • 36
  • 385
  • 444
  • Using one `Default` route when I go to the main page I get `HTTP Error 403.14 - Forbidden`. Is it possible to go to main page without ptoviding location parameter? – Mantas Čekanauskas Apr 10 '17 at 13:53
0

try adding a customroute before Default route

routes.MapRoute(
   name: "Location1Route",
   url: "{location}/{controller}/{action}",
   defaults: new { controller = "Home", action = "Index" }
);

this will match your need.

manish
  • 1,450
  • 8
  • 13
  • What if I don't want to be dependent on `loc1` and `loc2'? The actual `location` will be pulled from DB and HTML will be automatically renderred. – Mantas Čekanauskas Apr 10 '17 at 13:35
0

Have you considered hard coded default and a fail-safe routes?

routes.MapRoute("Home", "", new { controller = "Home", action = "Index" });
/*     Normal routing logic here     */
routes.MapRoute("FailSafe", "{*url}", new { controller = "Home", action = "Index"}); // !=Last Line=!
Mad Myche
  • 1,075
  • 1
  • 7
  • 15
0

Combined all answers and especially explanations I came up with this configuration

Route configuration:

routes.MapRoute(
    name: "DefaultShort",
    url: "{location}/",
    defaults: new { controller = "Products", action = "Index" }
);

routes.MapRoute(
    name: "Default",
    url: "{location}/{controller}/{action}/{id}",
    defaults: new { id = UrlParameter.Optional }
);

routes.MapRoute(
    name: "DefaultHome",
    url: "{controller}/{action}/",
    defaults: new { controller = "Home", action = "LandingPage"}
);

Some logic in OnActionExecuting

if (string.IsNullOrEmpty(location) 
    && cookie != null
    && !string.IsNullOrEmpty(cookie.Values["location"])
    && filterContext.ActionDescriptor.ActionName == "LandingPage"
    && filterContext.ActionDescriptor.ControllerDescriptor.ControllerName == "Home")
{
    filterContext.Result = new RedirectToRouteResult(
        new RouteValueDictionary
        {
            { "location", cookie.Values["location"]},
            { "controller", "Measurements" },
            { "action", "Index" }
        }
    );
}
else if (string.IsNullOrEmpty(location) 
    && filterContext.ActionDescriptor.ControllerDescriptor.ControllerName != "Home" 
    && !filterContext.IsChildAction)
{
    filterContext.Result = new RedirectToRouteResult(
        new RouteValueDictionary
        {
            { "controller", "Home" },
            { "action", "LandingPage" }
        }
}

If only location is provided, then it will use first route, which will redirect to the Products controller.

The second route will be used if all three location, controller and action parameters are matched in route. I have not provided default controller and action. This allows to use last route, when redirecting to HomeController.

The third route will have two parameters - controller and action, which allows me to get to a default view in HomeController. Using OnActionExecuting I'm redirecting to this default view and controller if it is not pointing to a HomeController and LandingPage.

Mantas Čekanauskas
  • 2,218
  • 6
  • 23
  • 43