【发布时间】:2011-07-31 22:52:12
【问题描述】:
我想设置路由如下:
/Profile/Edit -> 编辑操作的路径
/Profile/Add -> 添加操作的路由
/Profile/username -> 使用参数用户名路由到索引操作,因为操作用户名不存在。
所以我希望将第二个参数解析为控制器操作,除非不存在具有该名称的控制器;然后它应该路由到默认索引页面并使用 url 部分作为 id。
可能吗?
【问题讨论】:
我想设置路由如下:
/Profile/Edit -> 编辑操作的路径
/Profile/Add -> 添加操作的路由
/Profile/username -> 使用参数用户名路由到索引操作,因为操作用户名不存在。
所以我希望将第二个参数解析为控制器操作,除非不存在具有该名称的控制器;然后它应该路由到默认索引页面并使用 url 部分作为 id。
可能吗?
【问题讨论】:
一切皆有可能。但是,为什么不直接将 /profile 设为您的根目录?
如果这不可能,您可能需要硬编码您的操作路线。
【讨论】:
Matt 的解决方案可以帮助您完成 90% 的工作。但是,不要使用路由约束来排除操作名称,而是使用路由约束来仅包含有效的用户名,如下所示:
public class MustMatchUserName : IRouteConstraint
{
private Users _db = new UserEntities();
public MustMatchUserName()
{ }
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
return _db.Users.FirstOrDefault(x => x.UserName.ToLower() == values[parameterName].ToString().ToLower()) != null;
}
}
然后,正如 Matt 指出的那样,在用户创建过程中,您必须强制执行一个规则,即您的 ActionNames 对用户名无效。
辅导员
【讨论】:
您可以像这样在路由约束中使用正则表达式
routes.MapRoute(
"UserProfileRoute",
"Profile/{username}",
new { controller = "Profile", action = "Index" },
new { username = "(?i)(?!edit$|add$)(.*)" });
这将匹配像 /profile/addendum /profile/someusername 这样的网址,并将忽略 /profile/edit 和 /profile/add
【讨论】:
这是实现此目的的一种方法:
在 Global.asax.cs 中创建这些路线:
routes.MapRoute("UserProfileRoute", "Profile/{username}",
new { controller = "Profile", action = "Index" });
routes.MapRoute("DefaultProfileRoute", "Profile/{action}",
new { controller = "Profile", action = "SomeDefaultAction" });
这将按预期匹配 /Profile/someUsername。但是对于所有其他操作,它将失败。现在假定所有操作名称都是用户名。对此的快速解决方法是将 IRouteConstraint 添加到第一条路由:
routes.MapRoute("UserProfileRoute", "Profile/{username}",
new { controller = "Profile", action = "Index" },
new { username = new NotAnActionRouteConstraint() });
routes.MapRoute("DefaultProfileRoute", "Profile/{action}",
new { controller = "Profile", action = "SomeDefaultAction" });
public class NotAnActionRouteConstraint : IRouteConstraint
{
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
string value = values[parameterName].ToString();
// it is likely parameterName is not cased correctly,
// something that would need to be
// addressed in a real implementation
return typeof(ProfileController).GetMethod(parameterName,
BindingFlags.Public | BindingFlags.Instance) == null;
}
}
但是,这有点难看。希望有人知道更好的解决方案。
当您的某个用户选择与操作相同的名称时,您也会遇到问题 :)
【讨论】: