史上最全的ASP.NET MVC路由配置

2025-12-13 0 382

原文http://www.cnblogs.com/zeusro/p/RouteConfig.html装载注明出处,爬虫请自重。

继续延续坑爹标题系列。其实只是把apress.pro.asp.net.mvc.4.framework里的CHAPTER 13翻译过来罢了,当做自己总结吧。内容看看就好,排版就不要吐槽了,反正我知道你也不会反对的。

先说一下基本的路由规则原则。基本的路由规则是从特殊到一般排列,也就是最特殊(非主流)的规则在最前面,最一般(万金油)的规则排在最后。这是因为匹配路由规则也是照着这个顺序的。如果写反了,那么即便你路由规则写对了那照样坐等404.

XD 首先说URL的构造。 其实这个也谈不上构造,只是语法特性吧。

URL构造

命名参数规范+匿名对象

routes.MapRoute(name:\”Default\”,url:\”{controller}/{action}/{id}\”, defaults:new{ controller =\”Home\”, action =\”Index\”, id = UrlParameter.Optional } );

构造路由然后添加

1

2

Route myRoute =newRoute(\”{controller}/{action}\”,newMvcRouteHandler());

routes.Add(\”MyRoute\”, myRoute);

直接方法重载+匿名对象

1

routes.MapRoute(\”ShopSchema\”,\”Shop/{action}\”,new{ controller =\”Home\”});

  个人觉得第一种比较易懂,第二种方便调试,第三种写起来比较效率吧。各取所需吧。本文行文偏向于第三种。

路由规则

1.默认路由(MVC自带)

1

2

3

4

routes.MapRoute(

\”Default\”,// 路由名称

\”{controller}/{action}/{id}\”,// 带有参数的 URL

new{ controller =\”Home\”, action =\”Index\”, id = UrlParameter.Optional }// 参数默认值 (UrlParameter.Optional-可选的意思) );

2.静态URL段

1

2

3

4

5

routes.MapRoute(\”ShopSchema2\”,\”Shop/OldAction\”,new{ controller =\”Home\”, action =\”Index\”});

routes.MapRoute(\”ShopSchema\”,\”Shop/{action}\”,new{ controller =\”Home\”});

routes.MapRoute(\”ShopSchema2\”,\”Shop/OldAction.js\”,

new{ controller =\”Home\”, action =\”Index\”});

没有占位符路由就是现成的写死的。

比如这样写然后去访问http://localhost:XXX/Shop/OldAction.js,response也是完全没问题的。 controller , action , area这三个保留字就别设静态变量里面了。

3.自定义常规变量URL段(好吧这翻译暴露智商了)

1

routes.MapRoute(\”MyRoute2\”,\”{controller}/{action}/{id}\”,new{ controller =\”Home\”, action =\”Index\”, id =\”DefaultId\”});

这种情况如果访问 /Home/Index 的话,因为第三段(id)没有值,根据路由规则这个参数会被设为DefaultId

这个用viewbag给title赋值就能很明显看出

1

ViewBag.Title = RouteData.Values[\”id\”];

图不贴了,结果是标题显示为DefaultId。 注意要在控制器里面赋值,在视图赋值没法编译的。

4.再述默认路由

然后再回到默认路由。 UrlParameter.Optional这个叫可选URL段.路由里没有这个参数的话id为null。 照原文大致说法,这个可选URL段能用来实现一个关注点的分离。刚才在路由里直接设定参数默认值其实不是很好。照我的理解,实际参数是用户发来的,我们做的只是定义形式参数名。但是,如果硬要给参数赋默认值的话,建议用语法糖写到action参数里面。比如:

1

publicActionResult Index(stringid =\”abcd\”){ViewBag.Title = RouteData.Values[\”id\”];returnView();}

5.可变长度路由。

1

routes.MapRoute(\”MyRoute\”,\”{controller}/{action}/{id}/{*catchall}\”,new{ controller =\”Home\”, action =\”Index\”, id = UrlParameter.Optional });

在这里id和最后一段都是可变的,所以 /Home/Index/dabdafdaf 等效于 /Home/Index//abcdefdjldfiaeahfoeiho 等效于 /Home/Index/All/Delete/Perm/…..

6.跨命名空间路由

这个提醒一下记得引用命名空间,开启IIS网站不然就是404。这个非常非主流,不建议瞎搞。

1

routes.MapRoute(\”MyRoute\”,\”{controller}/{action}/{id}/{*catchall}\”,new{ controller =\”Home\”, action =\”Index\”, id = UrlParameter.Optional },new[] {\”URLsAndRoutes.AdditionalControllers\”,\”UrlsAndRoutes.Controllers\”});

但是这样写的话数组排名不分先后的,如果有多个匹配的路由会报错。 然后作者提出了一种改进写法。

1

2

3

routes.MapRoute(\”AddContollerRoute\”,\”Home/{action}/{id}/{*catchall}\”,new{ controller =\”Home\”, action =\”Index\”, id = UrlParameter.Optional },new[] {\”URLsAndRoutes.AdditionalControllers\”});

routes.MapRoute(\”MyRoute\”,\”{controller}/{action}/{id}/{*catchall}\”,new{ controller =\”Home\”, action =\”Index\”, id = UrlParameter.Optional },new[] {\”URLsAndRoutes.Controllers\”});

这样第一个URL段不是Home的都交给第二个处理 最后还可以设定这个路由找不到的话就不给后面的路由留后路啦,也就不再往下找啦。

1

2

3

4

Route myRoute = routes.MapRoute(\”AddContollerRoute\”,

\”Home/{action}/{id}/{*catchall}\”,

new{ controller =\”Home\”, action =\”Index\”, id = UrlParameter.Optional },

new[] {\”URLsAndRoutes.AdditionalControllers\”}); myRoute.DataTokens[\”UseNamespaceFallback\”] =false;

7.正则表达式匹配路由

1

2

3

4

routes.MapRoute(\”MyRoute\”,\”{controller}/{action}/{id}/{*catchall}\”,

new{ controller =\”Home\”, action =\”Index\”, id = UrlParameter.Optional },

new{ controller =\”^H.*\”},

new[] {\”URLsAndRoutes.Controllers\”});

约束多个URL

1

2

3

4

routes.MapRoute(\”MyRoute\”,\”{controller}/{action}/{id}/{*catchall}\”,

new{ controller =\”Home\”, action =\”Index\”, id = UrlParameter.Optional },

new{ controller =\”^H.*\”, action =\”^Index$|^About$\”},

new[] {\”URLsAndRoutes.Controllers\”});

8.指定请求方法

1

2

3

4

5

6

7

routes.MapRoute(\”MyRoute\”,\”{controller}/{action}/{id}/{*catchall}\”,

new{ controller =\”Home\”, action =\”Index\”, id = UrlParameter.Optional },

new{ controller =\”^H.*\”, action =\”Index|About\”, httpMethod =newHttpMethodConstraint(\”GET\”) },

new[] {\”URLsAndRoutes.Controllers\”});

9.WebForm支持

1

2

3

4

5

6

7

routes.MapPageRoute(\”\”,\”\”,\”~/Default.aspx\”);

routes.MapPageRoute(\”list\”,\”Items/{action}\”,\”~/Items/list.aspx\”,false,newRouteValueDictionary { {\”action\”,\”all\”} });

routes.MapPageRoute(\”show\”,\”Show/{action}\”,\”~/show.aspx\”,false,newRouteValueDictionary { {\”action\”,\”all\”} });

routes.MapPageRoute(\”edit\”,\”Edit/{id}\”,\”~/edit.aspx\”,false,newRouteValueDictionary { {\”id\”,\”1\”} },newRouteValueDictionary { {\”id\”,@\”\\d+\”} });

具体的可以看

使用Asp.Net4新特性路由创建WebForm应用

或者官方msdn

10.MVC5的RouteAttribute

首先要在路由注册方法那里

1

2

//启用路由特性映射

routes.MapMvcAttributeRoutes();

这样

1

[Route(\”Login\”)]

route特性才有效.该特性有好几个重载.还有路由约束啊,顺序啊,路由名之类的.

其他的还有路由前缀,路由默认值

1

[RoutePrefix(\”reviews\”)]<br>[Route(\”{action=index}\”)]<br>publicclassReviewsController : Controller<br>{<br>}

路由构造

1

2

3

4

5

6

7

// eg: /users/5

[Route(\”users/{id:int}\”]

publicActionResult GetUserById(intid) { … }

// eg: users/ken

[Route(\”users/{name}\”]

publicActionResult GetUserByName(stringname) { … }

参数限制

1

2

3

4

5

// eg: /users/5

// but not /users/10000000000 because it is larger than int.MaxValue,

// and not /users/0 because of the min(1) constraint.

[Route(\”users/{id:int:min(1)}\”)]

publicActionResult GetUserById(intid) { … }

Constraint Description Example
alpha Matches uppercase or lowercase Latin alphabet characters (a-z, A-Z) {x:alpha}
bool Matches a Boolean value. {x:bool}
datetime Matches aDateTimevalue. {x:datetime}
decimal Matches a decimal value. {x:decimal}
double Matches a 64-bit floating-point value. {x:double}
float Matches a 32-bit floating-point value. {x:float}
guid Matches a GUID value. {x:guid}
int Matches a 32-bit integer value. {x:int}
length Matches a string with the specified length or within a specified range of lengths. {x:length(6)} {x:length(1,20)}
long Matches a 64-bit integer value. {x:long}
max Matches an integer with a maximum value. {x:max(10)}
maxlength Matches a string with a maximum length. {x:maxlength(10)}
min Matches an integer with a minimum value. {x:min(10)}
minlength Matches a string with a minimum length. {x:minlength(10)}
range Matches an integer within a range of values. {x:range(10,50)}
regex Matches a regular expression. {x:regex(^\\d{3}-\\d{3}-\\d{4}$)}

具体的可以参考

Attribute Routing in ASP.NET MVC 5

对我来说,这样的好处是分散了路由规则的定义.有人喜欢集中,我个人比较喜欢这种灵活的处理.因为这个action定义好后,我不需要跑到配置那里定义对应的路由规则

11.最后还是不爽的话自己写个类实现 IRouteConstraint的匹配方法。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Linq;

usingSystem.Web;

usingSystem.Web.Routing;

/// <summary>

/// If the standard constraints are not sufficient for your needs, you can define your own custom constraints by implementing the IRouteConstraint interface.

/// </summary>

publicclassUserAgentConstraint : IRouteConstraint

{

privatestringrequiredUserAgent;

publicUserAgentConstraint(stringagentParam)

{

requiredUserAgent = agentParam;

}

publicboolMatch(HttpContextBase httpContext, Route route,stringparameterName,

RouteValueDictionary values, RouteDirection routeDirection)

{

returnhttpContext.Request.UserAgent !=null&&

httpContext.Request.UserAgent.Contains(requiredUserAgent);

}

}

1

2

3

4

5

6

7

routes.MapRoute(\”ChromeRoute\”,\”{*catchall}\”,

new{ controller =\”Home\”, action =\”Index\”},

new{ customConstraint =newUserAgentConstraint(\”Chrome\”) },

new[] {\”UrlsAndRoutes.AdditionalControllers\”});

比如这个就用来匹配是否是用谷歌浏览器访问网页的。

12.访问本地文档

1

2

3

routes.RouteExistingFiles =true;

routes.MapRoute(\”DiskFile\”,\”Content/StaticContent.html\”,new{ controller =\”Customer\”, action =\”List\”, });

浏览网站,以开启 IIS Express,然后点显示所有应用程序-点击网站名称-配置(applicationhost.config)-搜索UrlRoutingModule节点

1

<add name=\”UrlRoutingModule-4.0\”type=\”System.Web.Routing.UrlRoutingModule\”preCondition=\”managedHandler,runtimeVersionv4.0\”/>

把这个节点里的preCondition删除,变成

1

<add name=\”UrlRoutingModule-4.0\”type=\”System.Web.Routing.UrlRoutingModule\”preCondition=\”\”/>

13.直接访问本地资源,绕过了路由系统

1

routes.IgnoreRoute(\”Content/{filename}.html\”);

文件名还可以用 {filename}占位符。

IgnoreRoute方法是RouteCollection里面StopRoutingHandler类的一个实例。路由系统通过硬-编码识别这个Handler。如果这个规则匹配的话,后面的规则都无效了。 这也就是默认的路由里面routes.IgnoreRoute(\”{resource}.axd/{*pathInfo}\”);写最前面的原因。

路由测试(在测试项目的基础上,要装moq)

1

PM> Install-Package Moq

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

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

usingSystem;

usingMicrosoft.VisualStudio.TestTools.UnitTesting;

usingSystem.Web;

usingMoq;

usingSystem.Web.Routing;

usingSystem.Reflection;

[TestClass]

publicclassRoutesTest

{

privateHttpContextBase CreateHttpContext(stringtargetUrl =null,stringHttpMethod =\”GET\”)

{

// create the mock request

Mock<HttpRequestBase> mockRequest =newMock<HttpRequestBase>();

mockRequest.Setup(m => m.AppRelativeCurrentExecutionFilePath)

.Returns(targetUrl);

mockRequest.Setup(m => m.HttpMethod).Returns(HttpMethod);

// create the mock response

Mock<HttpResponseBase> mockResponse =newMock<HttpResponseBase>();

mockResponse.Setup(m => m.ApplyAppPathModifier(

It.IsAny<string>())).Returns<string>(s => s);

// create the mock context, using the request and response

Mock<HttpContextBase> mockContext =newMock<HttpContextBase>();

mockContext.Setup(m => m.Request).Returns(mockRequest.Object);

mockContext.Setup(m => m.Response).Returns(mockResponse.Object);

// return the mocked context

returnmockContext.Object;

}

privatevoidTestRouteMatch(stringurl,stringcontroller,stringaction,objectrouteProperties =null,stringhttpMethod =\”GET\”)

{

// Arrange

RouteCollection routes =newRouteCollection();

RouteConfig.RegisterRoutes(routes);

// Act – process the route

RouteData result = routes.GetRouteData(CreateHttpContext(url, httpMethod));

// Assert

Assert.IsNotNull(result);

Assert.IsTrue(TestIncomingRouteResult(result, controller, action, routeProperties));

}

privateboolTestIncomingRouteResult(RouteData routeResult,stringcontroller,stringaction,objectpropertySet =null)

{

Func<object,object,bool> valCompare = (v1, v2) =>

{

returnStringComparer.InvariantCultureIgnoreCase

.Compare(v1, v2) == 0;

};

boolresult = valCompare(routeResult.Values[\”controller\”], controller)

&& valCompare(routeResult.Values[\”action\”], action);

if(propertySet !=null)

{

PropertyInfo[] propInfo = propertySet.GetType().GetProperties();

foreach(PropertyInfo piinpropInfo)

{

if(!(routeResult.Values.ContainsKey(pi.Name)

&& valCompare(routeResult.Values[pi.Name],

pi.GetValue(propertySet,null))))

{

result =false;

break;

}

}

}

returnresult;

}

privatevoidTestRouteFail(stringurl)

{

// Arrange

RouteCollection routes =newRouteCollection();

RouteConfig.RegisterRoutes(routes);

// Act – process the route

RouteData result = routes.GetRouteData(CreateHttpContext(url));

// Assert

Assert.IsTrue(result ==null|| result.Route ==null);

}

[TestMethod]

publicvoidTestIncomingRoutes()

{

// check for the URL that we hope to receive

TestRouteMatch(\”~/Admin/Index\”,\”Admin\”,\”Index\”);

// check that the values are being obtained from the segments

TestRouteMatch(\”~/One/Two\”,\”One\”,\”Two\”);

// ensure that too many or too few segments fails to match

TestRouteFail(\”~/Admin/Index/Segment\”);//失败

TestRouteFail(\”~/Admin\”);//失败

TestRouteMatch(\”~/\”,\”Home\”,\”Index\”);

TestRouteMatch(\”~/Customer\”,\”Customer\”,\”Index\”);

TestRouteMatch(\”~/Customer/List\”,\”Customer\”,\”List\”);

TestRouteFail(\”~/Customer/List/All\”);//失败

TestRouteMatch(\”~/Customer/List/All\”,\”Customer\”,\”List\”,new{ id =\”All\”});

TestRouteMatch(\”~/Customer/List/All/Delete\”,\”Customer\”,\”List\”,new{ id =\”All\”, catchall =\”Delete\”});

TestRouteMatch(\”~/Customer/List/All/Delete/Perm\”,\”Customer\”,\”List\”,new{ id =\”All\”, catchall =\”Delete/Perm\”});

}

}

  最后还是再推荐一下Adam Freeman写的apress.pro.asp.net.mvc.4这本书。稍微熟悉MVC的从第二部分开始读好了。前面都是入门(对我来说是扯淡)。但总比国内某些写书的人好吧——把个开源项目的源代码下载下来帖到书上面来,然后标题起个深入解析XXXX,然后净瞎扯淡。最后一千多页的巨著又诞生了。Adam Freeman的风格我就很喜欢,都是实例写作,然后还在那边书里面专门写了大量的测试。

  哎没办法啊,技术差距就是这样了。

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

申明:本文由第三方发布,内容仅代表作者观点,与本网站无关。对本文以及其中全部或者部分内容的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。本网发布或转载文章出于传递更多信息之目的,并不意味着赞同其观点或证实其描述,也不代表本网对其真实性负责。

左子网 编程相关 史上最全的ASP.NET MVC路由配置 https://www.zuozi.net/36445.html

常见问题
  • 1、自动:拍下后,点击(下载)链接即可下载;2、手动:拍下后,联系卖家发放即可或者联系官方找开发者发货。
查看详情
  • 1、源码默认交易周期:手动发货商品为1-3天,并且用户付款金额将会进入平台担保直到交易完成或者3-7天即可发放,如遇纠纷无限期延长收款金额直至纠纷解决或者退款!;
查看详情
  • 1、描述:源码描述(含标题)与实际源码不一致的(例:货不对板); 2、演示:有演示站时,与实际源码小于95%一致的(但描述中有”不保证完全一样、有变化的可能性”类似显著声明的除外); 3、发货:不发货可无理由退款; 4、安装:免费提供安装服务的源码但卖家不履行的; 5、收费:价格虚标,额外收取其他费用的(但描述中有显著声明或双方交易前有商定的除外); 6、其他:如质量方面的硬性常规问题BUG等。 注:经核实符合上述任一,均支持退款,但卖家予以积极解决问题则除外。
查看详情
  • 1、左子会对双方交易的过程及交易商品的快照进行永久存档,以确保交易的真实、有效、安全! 2、左子无法对如“永久包更新”、“永久技术支持”等类似交易之后的商家承诺做担保,请买家自行鉴别; 3、在源码同时有网站演示与图片演示,且站演与图演不一致时,默认按图演作为纠纷评判依据(特别声明或有商定除外); 4、在没有”无任何正当退款依据”的前提下,商品写有”一旦售出,概不支持退款”等类似的声明,视为无效声明; 5、在未拍下前,双方在QQ上所商定的交易内容,亦可成为纠纷评判依据(商定与描述冲突时,商定为准); 6、因聊天记录可作为纠纷评判依据,故双方联系时,只与对方在左子上所留的QQ、手机号沟通,以防对方不承认自我承诺。 7、虽然交易产生纠纷的几率很小,但一定要保留如聊天记录、手机短信等这样的重要信息,以防产生纠纷时便于左子介入快速处理。
查看详情

相关文章

猜你喜欢
发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务