您的位置:首页 > 编程语言 > ASP

ASP.NET MVC:自定义 Route 让你的 Url 更优雅

2016-04-03 22:50 756 查看
如今,互联网越来越注重简单优雅的 Url,对比下面两个:

~/Products/UpdateUnitPrice/5
~/products/update-unit-price/5

我相信大多数朋友会更喜欢第二种方式:小写,使用负(减)号作为连字符。

本文使用自定义 Route 来达到方式二的效果,只需增加几个类和简单修改下 global.asax 文件。


Route 是双向的

Route 的基本概念我就不多说了,这里重点强调一下 ASP.NET MVC 中 Route 是双向的,这可以从 RouteBase 类的定义可以看出:
1
2
3
4

public abstract class RouteBase{
public abstract RouteData GetRouteData(HttpContextBase httpContext);
public abstract VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values);
}

GetRouteData 用于解析 Url,GetVirtualPath 用于生成 Url。

在开始编写我们的 Route 类之前,我们需要一个用于处理字符串的静态类:


StringElegantHelper 类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

internal static class StringElegantHelper {

public static readonly char minus = '-';

public static string Elegant(string s) {
var builder = new StringBuilder();
var index = 0;
foreach (var c in s) {
if (c >= 'A' && c <= 'Z') {
if (index > 0) builder.Append(minus);
builder.Append(char.ToLower(c));
}
else if (c == minus) {
builder.Append(minus);
builder.Append(minus);
}
else
builder.Append(c);
index++;
}
return builder.ToString();
}

public static string DeElegant(string s) {
var builder = new StringBuilder();
var iterator = s.GetEnumerator();
while (iterator.MoveNext()) {
if (iterator.Current != minus) {
builder.Append(iterator.Current);
continue;
}
if (!iterator.MoveNext()) {
builder.Append(minus);
break;
}
if (iterator.Current == minus)
builder.Append(minus);
else
builder.Append(iterator.Current);
}
return builder.ToString();
}
}

StringElegantHelper 中有两个方法 Elegant 和 DeElegant,将分别用在 GetVirtualPath 和 GetRouteData 方法中,用于生成和解析优雅的 Url。

这两方法也可以使用正则表达式来实现,但我认为效率不高,就采用了上面这种最朴实的方式。

有了 StringElegantHelper 类,写出 ElegantRoute 就简单多了:


ElegantRoute 类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

public class ElegantRoute : Route {

public static readonly string[] ToElegant =  new [] { "controller", "action" };

public ElegantRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, RouteValueDictionary dataTokens, IRouteHandler routeHandler)
: base(url, defaults, constraints, dataTokens, routeHandler) { }

public override RouteData GetRouteData(HttpContextBase httpContext) {
var result = base.GetRouteData(httpContext);
if (result == null) return null;

foreach (var key in ToElegant)
HandleItem(result.Values, key, StringElegantHelper.DeElegant);
return result;
}

public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values) {
var elegantValues = new RouteValueDictionary(values);
foreach (var key in ToElegant)
HandleItem(elegantValues, key, StringElegantHelper.Elegant);
return base.GetVirtualPath(requestContext, elegantValues);
}

private void HandleItem(RouteValueDictionary dict, string key, Func<string, string> handler) {
if (!dict.ContainsKey(key)) return;
//
var value = dict[key];
if (!(value is string)) return;
//
dict[key] = handler(value as string);
}
}

注意,上面代码中只对 controller 和 action 的路由值进行了“优雅”处理,其它值并没有,为什么呢?

大家可以考虑以下网址:

~/customers/details/ANTON

全部处理的话会变成:

~/customers/details/a-n-t-o-n

代码其他部分比较简单,不多说了。

最后,还需要几个扩展方法,以方便在 global.asax 文件中使用:


ElegantRouteExtensions 类

1
2
3
4
5
6
7
8
9
10
11

public static class ElegantRouteExtensions {
public static ElegantRoute MapElegantRoute(this RouteCollection routes, string name, string url, object defaults) {
var route = new ElegantRoute(url,
new RouteValueDictionary(defaults),
new RouteValueDictionary(), //constraints
new RouteValueDictionary(), //dataTokens
new MvcRouteHandler());
routes.Add(name, route);
return route;
}
}

我只写出一个,大家可根据需要添加。


使用 ElegantRouter

借助上面的扩展方法,使用就很相当简单了。

global.asax 文件中,把 routes.MapRoute 替换为 routes.MapElegantRoute 即可:
1
2
3
4
5

routes.MapElegantRoute(  // MapRoute
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);

运行起来验证,点下右上角的 [ Log On ] 链接:





ElegantRoute 生成和解析通过。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: