0%

【MVC】Router Constraint

當今天有個網址的需求是 http://abcdefg.com/【使用者暱稱】,使用者暱稱帶到誰的就會到個人頁網址,EX : http://abcdefg.com/toyo 就連到Toyo個人頁面,http://abcdefg.com/steven就連到Steven個人頁,那我們Router可以寫成

1
2
3
4
5
6
7
[Route("~/toyo")]
[Route("~/steven")]
public ActionResult Content()
{
return View();
}

這樣寫的確兩個網址都能連到了,但卻抓不到UserName所以不知道怎麼顯示個人頁,調整一下

1
2
3
4
5
6
7
[Route("~/{UserName}")]
public ActionResult Content(string userName)
{
ViewBag.Name = userName;
return View();
}

下個問題來了,Tom明明不是這邊的用戶,卻也會導到這個Action,導致後端抓不到對應資料顯示錯誤,能不能只有abcdefg.com/Toyo 跟 abcdefg.com/Steven 的時候才導來這,其他什麼阿貓阿狗,甚至是常用的Index、Home、Menu之類的不會跑錯。

這時候RouteConstraint就派上用場了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class UserNameConstraint : IRouteConstraint
{
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
if (values.ContainsKey(parameterName))
{
var UserName = values[parameterName] as string;

return UserName.ToLower() == "toyo" ||
UserName.ToLower() == "steven";
}

return false;
}
}

接著在RouteConfig註冊這組Constraint,讓RouteAttribute可以使用

1
2
3
4
5
6
7
8
9
10
11
12
13
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

//註冊Router ConStraint
var constraintsResolver = new DefaultInlineConstraintResolver();
constraintsResolver.ConstraintMap.Add("MustUserName", typeof(UserNameConstraint));
routes.MapMvcAttributeRoutes(constraintsResolver);
}
}

將RouteAttribute的UserName加上這個限制

1
2
3
4
5
6
7
[Route("~/{UserName:MustUserName}")]
public ActionResult MyContent(string userName)
{
ViewBag.Name = userName;
return View();
}

這樣只要UserName不是帶Toyo或是Steven的就都不會導到這個Action了。

其實RouteConstraint官方已經提供一下基礎的限制可以使用,例如一定要是Int,字串長度之類的方便用法,而且更重要的是在這案例之中,使用者名稱我們是寫死的,只要把那段改成抓外部來源,例如資料庫之類的,這樣就能後台使用者有新增時,Route的限制就自動更新了

延伸閱讀:
Attribute Routing in ASP.NET MVC 5
DemoShop : ASP.NET MVC Route 自訂限制條件(constraints)的技巧