我有两条路线
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" }
);
当用户转到主页时,他必须选择两个链接:
<a href="/loc1/Products/index">Location 1</a>
<a href="/loc2/Products/index">Location 2</a>
我也有ActionFilterAttribute
,我在其中检查location
参数,如果 url 没有它,我会将用户重定向到主页。
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);
}
根据location
变量,我将从数据库中查询不同的记录,因此当用户在 url 中不提供任何位置并尝试访问Products/index/5
我希望他们被重定向到他们必须选择位置并单击其中一个链接的主页。 但是我收到错误消息:
找不到资源。
说明:HTTP 404。要查找的资源(或其依赖项之一)可能已被删除、名称已更改或暂时不可用。 请查看以下 URL 并确保拼写正确。
请求的网址:/产品/索引
我应该如何正确配置路由,以便在 url 中没有位置参数的情况下将用户重定向到主页?
您的"默认"路线(包括位置)是唯一会被击中的路线。controller
、action
和id
参数都是可选的,因此对类似/Products/Index
的请求实际上将被您的"默认"路由捕获,并且location
参数将被赋予"产品",您的controller
参数将被赋予"索引"作为值。action
参数将是"索引"的默认值,id
参数将被忽略。由于您显然没有具有Index
操作的IndexController
,因此您将获得404。
要区分路由,您需要使您的"默认"路由需要某种硬编码前缀,即
routes.MapRoute(
name: "Default",
url: "location/{location}/{controller}/{action}/{id}",
defaults: new { controller = "Products", action = "Index", id = UrlParameter.Optional }
);
然后,/Products/Index
路线将落入您的"主页"路线,并被正确解释为通往ProductsController.Index
的路线。或者,您可以将路由约束应用于location
参数,因此它不会匹配所有内容,即:
routes.MapRoute(
name: "Default",
url: "{location}/{controller}/{action}/{id}",
defaults: new { controller = "Products", action = "Index", id = UrlParameter.Optional },
constraints: new { location = @"^(loc1|loc2)$" }
);
然后,除非URL的第一部分与loc1
或loc2
匹配,否则它将落入"Home"路由。
您是否考虑过硬编码的默认路由和故障安全路由?
routes.MapRoute("Home", "", new { controller = "Home", action = "Index" });
/* Normal routing logic here */
routes.MapRoute("FailSafe", "{*url}", new { controller = "Home", action = "Index"}); // !=Last Line=!
尝试在Default
路由之前添加自定义route
routes.MapRoute(
name: "Location1Route",
url: "{location}/{controller}/{action}",
defaults: new { controller = "Home", action = "Index" }
);
这将满足您的需求。
结合所有答案,尤其是解释,我想出了这个配置
路由配置:
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"}
);
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" }
}
}
如果仅提供位置,则它将使用第一个路由,该路由将重定向到Products
控制器。
如果路由中的所有三个location
、controller
和action
参数都匹配,则将使用第二条路由。我没有提供默认controller
和action
。这允许在重定向到HomeController
时使用最后的路由。
第三条路线将有两个参数 -controller
和action
,这使我可以在HomeController
中获取默认视图。使用OnActionExecuting
,如果它不指向HomeController
和LandingPage
,我将重定向到此默认视图和控制器。