1. 程式人生 > >史上最全的ASP.NET MVC路由配置,以後RouteConfig再弄不懂神仙都難救你啦

史上最全的ASP.NET MVC路由配置,以後RouteConfig再弄不懂神仙都難救你啦

繼續延續坑爹標題系列。其實只是把apress.pro.asp.net.mvc.4.framework裡的CHAPTER 13翻譯過來罷了,當做自己總結吧。內容看看就好,排版就不要吐槽了,反正我知道你也不會反對的。

XD 首先說URL的構造。 其實這個也談不上構造,只是語法特性吧。

命名引數規範+匿名物件

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

構造路由然後新增

Route myRoute = new Route("{controller}/{action}", new MvcRouteHandler()); routes.Add("MyRoute", myRoute);

直接方法過載+匿名物件

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

個人覺得第一種比較易懂,第二種方便除錯,第三種寫起來比較效率吧。各取所需吧。本文行文偏向於第三種。

1.預設路由(MVC自帶)

routes.MapRoute( "Default", //
路由名稱 "{controller}/{action}/{id}", // 帶有引數的 URL new { controller = "Home", action = "Index", id = UrlParameter.Optional } // 引數預設值 (UrlParameter.Optional-可選的意思) );

2.靜態URL段

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段(好吧這翻譯暴露智商了)

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

這種情況如果訪問 /Home/Index 的話,因為第三段(id)沒有值,根據路由規則這個引數會被設為DefaultId

這個用viewbag給title賦值就能很明顯看出

ViewBag.Title = RouteData.Values["id"];

圖不貼了,結果是標題顯示為DefaultId。 注意要在控制器裡面賦值,在檢視賦值沒法編譯的。

4.再述預設路由

然後再回到預設路由。 UrlParameter.Optional這個叫可選URL段.路由裡沒有這個引數的話id為null。 照原文大致說法,這個可選URL段能用來實現一個關注點的分離。剛才在路由裡直接設定引數預設值其實不是很好。照我的理解,實際引數是使用者發來的,我們做的只是定義形式引數名。但是,如果硬要給引數賦預設值的話,建議用語法糖寫到action引數裡面。比如:

public ActionResult Index(string id = "abcd") { ViewBag.Title = RouteData.Values["id"]; return View(); }

5.可變長度路由。

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。這個非常非主流,不建議瞎搞。

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

但是這樣寫的話陣列排名不分先後的,如果有多個匹配的路由會報錯。 然後作者提出了一種改進寫法。

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的都交給第二個處理 最後還可以設定這個路由找不到的話就不給後面的路由留後路啦,也就不再往下找啦。

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.正則表示式匹配路由

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

約束多個URL

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.指定請求方法

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

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

new { controller = "^H.*", action = "Index|About", httpMethod = new HttpMethodConstraint("GET") }, 

new[] { "URLsAndRoutes.Controllers" });

9.最後還是不爽的話自己寫個類實現 IRouteConstraint的匹配方法。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.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>
public class UserAgentConstraint : IRouteConstraint
{

private string requiredUserAgent;
public UserAgentConstraint(string agentParam)
{
requiredUserAgent = agentParam;
}
public bool Match(HttpContextBase httpContext, Route route, string parameterName,
RouteValueDictionary values, RouteDirection routeDirection)
{
return httpContext.Request.UserAgent != null &&
httpContext.Request.UserAgent.Contains(requiredUserAgent);
}
}
routes.MapRoute("ChromeRoute", "{*catchall}", 

new { controller = "Home", action = "Index" }, 

new { customConstraint = new UserAgentConstraint("Chrome") }, 

new[] { "UrlsAndRoutes.AdditionalControllers" });

比如這個就用來匹配是否是用谷歌瀏覽器訪問網頁的。

10.訪問本地文件

routes.RouteExistingFiles = true; 

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

瀏覽網站,以開啟 IIS Express,然後點顯示所有應用程式-點選網站名稱-配置(applicationhost.config)-搜尋UrlRoutingModule節點

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

把這個節點裡的preCondition刪除,變成

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

11.直接訪問本地資源,繞過了路由系統

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

檔名還可以用 {filename}佔位符。

IgnoreRoute方法是RouteCollection裡面StopRoutingHandler類的一個例項。路由系統通過硬-編碼識別這個Handler。如果這個規則匹配的話,後面的規則都無效了。 這也就是預設的路由裡面routes.IgnoreRoute("{resource}.axd/{*pathInfo}");寫最前面的原因。

路由測試(在測試專案的基礎上,要裝moq)

PM> Install-Package Moq
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Web;
using Moq;
using System.Web.Routing;
using System.Reflection;
[TestClass]
public class RoutesTest
{
private HttpContextBase CreateHttpContext(string targetUrl = null, string HttpMethod = "GET")
{
// create the mock request
Mock<HttpRequestBase> mockRequest = new Mock<HttpRequestBase>();
mockRequest.Setup(m => m.AppRelativeCurrentExecutionFilePath)
.Returns(targetUrl);
mockRequest.Setup(m => m.HttpMethod).Returns(HttpMethod);
// create the mock response
Mock<HttpResponseBase> mockResponse = new Mock<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 = new Mock<HttpContextBase>();
mockContext.Setup(m => m.Request).Returns(mockRequest.Object);
mockContext.Setup(m => m.Response).Returns(mockResponse.Object);
// return the mocked context
return mockContext.Object;
}

private void TestRouteMatch(string url, string controller, string action, object routeProperties = null, string httpMethod = "GET")
{
// Arrange
RouteCollection routes = new RouteCollection();
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));
}

private bool TestIncomingRouteResult(RouteData routeResult, string controller, string action, object propertySet = null)
{
Func<object, object, bool> valCompare = (v1, v2) =>
{
return StringComparer.InvariantCultureIgnoreCase
.Compare(v1, v2) == 0;
};
bool result = valCompare(routeResult.Values["controller"], controller)
&& valCompare(routeResult.Values["action"], action);
if (propertySet != null)
{
PropertyInfo[] propInfo = propertySet.GetType().GetProperties();
foreach (PropertyInfo pi in propInfo)
{
if (!(routeResult.Values.ContainsKey(pi.Name)
&& valCompare(routeResult.Values[pi.Name],
pi.GetValue(propertySet, null))))
{
result = false;
break;
}
}
}
return result;
}

private void TestRouteFail(string url)
{
// Arrange
RouteCollection routes = new RouteCollection();
RouteConfig.RegisterRoutes(routes);
// Act - process the route
RouteData result = routes.GetRouteData(CreateHttpContext(url));
// Assert
Assert.IsTrue(result == null || result.Route == null);
}

[TestMethod]
public void TestIncomingRoutes()
{
// 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的風格我就很喜歡,都是例項寫作,然後還在那邊書裡面專門寫了大量的測試。

相關推薦

ASP.NET MVC路由配置以後RouteConfig神仙~

繼續延續坑爹標題系列。其實只是把apress.pro.asp.net.mvc.4.framework裡的CHAPTER 13翻譯過來罷了,當做自己總結吧。內容看看就好,排版就不要吐槽了,反正我知道你也不會反對的。 先說一下基本的路由規則原則。基本的路由規則是

ASP.NET MVC路由配置以後RouteConfig神仙

繼續延續坑爹標題系列。其實只是把apress.pro.asp.net.mvc.4.framework裡的CHAPTER 13翻譯過來罷了,當做自己總結吧。內容看看就好,排版就不要吐槽了,反正我知道你也不會反對的。 XD 首先說URL的構造。 其實這個也談不上構造,只是語

自學MVC看這裡——全網ASP.NET MVC 教程彙總

MVC架構已深得人心,微軟也不甘落後,推出了ASP.NET MVC。小編特意整理部落格園乃至整個網路最具價值的MVC技術原創文章,為想要學習ASP.NET MVC技術的學習者提供一個整合學習入口。本文從Why,What,How三個角度整理MVC 的學習資源,讓學習者第一時間找到最有價值的文章,獲取最徹底的

華為路由器交換機配置命令大合集

uid info rtt duplex display telnet facet sna its 華為路由器交換機配置命令是大家使用時經常遇到的,顧名思義關於交換機的計算機命令,路由器命令,交換機命令和動靜態命令都將在文中提到。 【限時免費】年底最強一次雲計算大會,看傳

新手必看的iOS開發教程集錦沒有之一!

最近大火的iPhone XS Max和iPhone XS,不知道有沒有同學已經下手了呢?一萬三的價位確實讓很多人望而卻步啊。據說為了贏得中國的使用者,專門出了雙卡雙待的,可想而知中國市場這塊“肥肉”人人都想要。 近幾年,無論蘋果出什麼樣的產品以及多高的價位,都會有非常多的蘋

淺析ASP.NET MVC路由配置

URL相關概念       http://example.com/albums/list.aspx  我們可以確定該站點的目錄中含有一個albums資料夾,並且在該資料夾下還有一個list.aspx

送福利|ZStack雲端計算學習資料社群使用者吐血整理!

為大家奉上辛苦整理許久的ZStack產品技術學習資源,聽兄弟一句,早晚用的上(語重心長臉) 一、軟體下載傳送門: ZStack官

【轉載】:TensorFlow 好玩的技術、應用和知道的黑科技

tube map 高性能 知識 seq 出現 執行時間 mes lex 【導讀】TensorFlow 在 2015 年年底一出現就受到了極大的關註,經過一年多的發展,已經成為了在機器學習、深度學習項目中最受歡迎的框架之一。自發布以來,TensorFlow 不斷在完善並增加新

: svn與git的對照(二):svn與git的相關概念

fill 來看 out avi head clas 相關 iss b2c 如圖1是svnserver端數據的文件夾結構 以下是gitserver端的文件夾結構 縱觀svn和git服務端的文件夾結構我們非常easy發現 1.有些目錄還是蠻像的。甚

React Native常用第三方組件匯總-- 之一

提示 存儲 ext upload body ner board pup wan 把我認為最好的知識,拿來與他人分享,是這一生快事之一! React Native 項目常用第三方組件匯總: react-native-animatable 動畫 react-na

掛載文件系統出現"kernel panic..." 解決方案

某個文件 table sha mount nic mic 2.6 完成 又是   問:掛載自己制作的文件系統卡在這裏:    NET: Registered protocol family 1    NET: Registered protocol family 17   

的Ajax

tool 復制 last 毫秒 如何實現 mon adding ast turn 本章內容: 簡介 偽 AJAX 原生 AJAX XmlHttpRequest 的屬性、方法、跨瀏覽器支持 jQuery AJAX 常用方法 跨域 AJAX JsonP

oracle表空間查詢維護命令大全之中的一個(數據表空間)

ava 劃分 man max rac 帳戶 oca nio msi 表空間是數據庫的邏輯劃分,一個表空間僅僅能屬於一個數據庫。全部的數據庫對象都存放在建立指定的表空間中。但主要存放的是表, 所以稱作表空間。在oracle 數據庫中至少存在

的變量、作用域和內存問題

分配 data () pen ole 創建 最全 操作符 釋放內存 (一)JavaScript變量能夠用來保存兩種類型的值:基本類型值和引用類型值。基本類型的值源自下面5種基本數據類型:Undefined、Null、Boolean、Number和 Str

Html和CSS布局技巧

喜歡 輸出 隔離 init scale ext med 兩種 float 單列布局水平居中 水平居中的頁面布局中最為常見的一種布局形式,多出現於標題,以及內容區域的組織形式,下面介紹四種實現水平居中的方法(註:下面各個實例中實現的是child元素的對齊操作,child元素的

轉: 作者 李艷鵬: 的架構師圖譜

-s -a ddd java se http 聯網 hadoop -c clas 本文是筆者多年來積累和收集的知識技能圖譜,有的是筆者原創總結的最佳實踐,有的是小夥伴們的分享,其中每個秘籍圖譜裏面的內容都是互聯網高並發架構師應該了解和掌握的知識,筆者索性把這些圖譜收集在

程序員進階路上能錯過的技術知識圖譜秘籍

容器 互聯網 def 1.3 java架構師 方法 分享 開發技能 2.4 今天在技術大海中遊啊遊遊啊遊,哇啊哈哈 ^_^發現了一份非常有用的超級技術圖譜誒! 強烈推薦啊!!本文原作者是易寶支付技術經理/架構師李艷鵬,這是鵬哥多年來積累和收集的技術知識技能圖譜,有的是鵬哥原

正確的zabbix server安裝過程

zabbix安裝 zabbix server 說在前面的話:本例使用的是centos7、zabbix2.2.6版本,其他版本需要再驗證不要使用yum安裝tomcat和jdk,否則安裝zabbix會報錯正文:一、Lamp安裝及準備工作yum -y install httpd mysql mysql-se

的JAVA面試總結

java數據庫類作為後端開發,可以說數據庫是重之又重。提問的比例也相當之大。所以這裏先記錄下這個。如何快速導入10萬條數據到MySQL數據庫?這個應該當時很緊張,居然半天說不出來。其實當時心裏有一個答案了,就是存儲過程。但是因為平常開發基本上沒用到過這東西,所以都不敢說了。。網上還有有一些答案說批處理,通過s

強SpringMVC詳細示例實戰教程

tin turn 方法 流程圖 瀏覽器 學習 this b- converter SpringMVC學習筆記---- 一、SpringMVC基礎入門,創建一個HelloWorld程序 1.首先,導入SpringMVC需要的jar包。 2.添加Web.xm