【ASP.NET Core】给路由规则命名有何用处
上一篇中老周給伙伴們介紹了自定義視圖搜索路徑的方法,本篇咱們扯一下有關(guān) URL 路徑規(guī)則的名稱問題。在扯今天的話題之前,先補充點東東。在上一篇中設(shè)置視圖搜索路徑時用到三個有序參數(shù):{2}{1}{0},分別是 Area、Controller、Action。其中說到幾個特殊的視圖,如_Layout.cshtml、_ViewStart.cshtml等。_Layout.cshtml 頁默認(rèn)放在 /Views/Shared 目錄下,但,_ViewStart.cshtml 和 _ViewImports.cshtml 這兩個不應(yīng)該放在 Shared 目錄下,一般應(yīng)放到 /Views 下,這樣它們可以作用于所有的視圖。如果放到了 Shared 目錄下,它們只對 Shared 目錄中的視圖起作用,而對于 Views 下的其他視圖不起作用。
比如,放到 /Views 下。
Views(目錄)│ ?_ViewImports.cshtml│ ?_ViewStart.cshtml│ ?└─Home(目錄,Controller的名字)Index.cshtml(視圖,Action)其中,Home 是子目錄,對應(yīng)著控制器 Home,Home 中的 Index.cshtml 視圖對應(yīng)著 Action 名 Index。此時,_ViewStart 和 _ViewImports 中的內(nèi)容會應(yīng)用到 /Views 下的所有視圖中(如 Index.cshtml)。
要是改為這樣。
Views
? ? ├─Home
? ? │? ? ? About.cshtml
? ? │? ? ? Index.cshtml
? ? │? ? ? _ViewImports.cshtml
? ? │? ? ? _ViewStart.cshtml
? ? │? ? ??
? ? └─Users
? ? ? ? ? ? AddNew.cshtml
此時,Views 有兩個子目錄,Home 是一個控制器,Users 是另一個控制器,這時候,_ViewStart 和 _ViewImports 只對 Home 下面的視圖起作用,對 Users 目錄下的視圖是不起作用的。
_ViewStart 主要用途是在所有視圖文件執(zhí)行之前執(zhí)行,一般我們用它來設(shè)置 Layout 屬性,以指定使用的布局頁(相當(dāng)于頁面母板),這樣一來,我們不需要在每個視圖上都加 Layout = "xxxx" 了。_ViewImports 主要是用來引入要用到的命名空間(就是 C# 中的 using),這樣你不需要在每個視圖中寫一堆 @using Razor 標(biāo)記了。
這兩個文件都是約定式的,所以你不應(yīng)該隨便改它的名字,_ViewImports 可以通過?RazorTemplateEngineOptions 類的 ImportsFileName 屬性來修改,不過,_ViewStart 好像不能改,老周看到 asp.net core 源碼中是寫死了的,估計是不能改文件名的。
其實,這兩個文件不應(yīng)該改名,而且你改了名字也沒啥用,反正功能是不變的,還是遵守約定好一些,這樣人家看你的項目時也看得懂。_Layout.cshtml 文件如非必要,也不應(yīng)該改名字,如果你的應(yīng)用要用多個布局視圖,可能建個子目錄,然后每個子目錄下放_Layout,這樣結(jié)構(gòu)清晰一些,畢竟,看到 _Layout.cshtml 就明白它是母板頁了。
?
規(guī)則模板
我們都知道,在 Startup.Configure 方法中,會以此方式來指定 URL 路徑規(guī)則。
app.UseMvc(route =>{route.MapRoute("main", "{controller=Students}/{action=List}/{sid?}");route.MapRoute("edit_post", "{controller}-{action}");});你可以添加 K 條規(guī)則,比如上面的例子,我添加了兩條規(guī)則。
{controller} 和 {action} 是約定的名稱,用來識別 Controller 和 Action ,所以你不要自作聰明亂來,必要有些寫死了的參數(shù)才能進行 URL 分析,不然,你給個 URL http://dog.org/shopping/pay/500,那應(yīng)用程序根本不知道哪一段是表示 Controller,哪一段是表示 action。
如果確定了 controller 和 action 這兩個值,那么其他的參數(shù)就好分析了。
其他參數(shù)如果是可選的,可以在后面加個問號,比如 {controller}/{action}/{id?},這表示 id 的值是可選的。
上面老周添加的兩個規(guī)則中,edit_post 那個其實不太規(guī)范,URL 中各段最好用 “/” 來分隔,因為 “-” 有時候是不允許用的,比如,id 參數(shù)前面就不能用,你不能寫成 {controller}-{action}-{id?},要是 id 中包含了字符“-”,咋辦呢?而“/”則不同,URL Encode 后不會冒出這個字符來。
所以用 / 最好,這里用 - 只是老周故意用來演示而已,URL 嘛,沒必要玩花樣,沒意義。
?
基于 Attribute 指定的 URL 路由
在 Startup.Configure 方法中指定的 URL 路由是作用于整個應(yīng)用程序的,如果想為個別控制器或個別 Action 指定路由規(guī)則,那么可以考慮使用 Attribute 的形式。
attribute 形式的路由規(guī)則和應(yīng)用程序級別的規(guī)則相似,只是,在應(yīng)用級別時,用大括號來包裹參數(shù)名(如 {controller}),而在 Attribute 方案中,是用中括號的,它只能用兩個值:[controller]、[action]。其他參數(shù)也是用大括號。比如,[controlloer]/[action]/[id?] 會報錯,你得改為 [controller]/[action]/{id?}。
RouteAttribute 既可以用于 Controller 類型,也可能用于單個 Action 方法上。我舉個例子,像這樣。
[Route("hello/[controller]/[action]")]
? ? public class SomethingController : Controller
? ? {
? ? ? ? [Route("{name?}")]
? ? ? ? public IActionResult SayHi(string name)
? ? ? ? {
? ? ? ? ? ? ……
? ? ? ? }
? ? }
在類上應(yīng)用用的 Attribute 中,可以使用這樣的 URL :http://localhost:999/hello/something/sayhi 。而在 SayHi 方法上,又用了 Route Attribute,指定了一個附加參數(shù) name,并且是可選的。于是它可以與類上的 Route attribute 合并,變成:http://localhost:999/hello/something/sayhi/Peter。這時,字符串 Peter 會傳給 SayHi 方法的 name 參數(shù),因為,參數(shù)的名字與 Route 中的參數(shù)名是相同的,都叫 name。如果 SayHi 中的參數(shù)名不叫 name,那你得運用一下?FromRouteAttribute 了。就像這樣。
[Route("{name?}")] ? ? ? ?public IActionResult SayHi([FromRoute(Name = "name")]string who){……}如果你希望 URL 中給 name 傳入 int 類型的值,你還可以限制它。
[Route("{name:int}")]其實這些約束條件對應(yīng)的是?Microsoft.AspNetCore.Routing.Constraints 命名空間下面的類型。
?
Route Data
Route data 其實就是一個字典,存放的就是 URL 路徑規(guī)則中參數(shù)與值的 key-value 對。這個很簡單,我舉個例子,你就明白了。
咱們就直接用上面那個例子吧。
[Route("hello/[controller]/[action]")]
? ? public class SomethingController : Controller
? ? {
? ? ? ? [Route("{name?}")]
? ? ? ? public IActionResult SayHi([FromRoute(Name = "name")]string who)
? ? ? ? {
? ? ? ? ? ? return Json(RouteData.Values);
? ? ? ? }
? ? }
在 SayHi 方法中,咱們把 route data 返回。
運行應(yīng)用后,輸入地址:http://localhost/hello/something/sayhi/Tom,得到的輸出如下:
不用我解釋了吧。
?
給路由命名
上面的都是 F 話,本小節(jié)才是本文的主題。我們回頭看看上面老周舉過例的那個 route。
app.UseMvc(route =>{route.MapRoute("main", "{controller=Students}/{action=List}/{sid?}");route.MapRoute("edit_post", "{controller}-{action}");});每條路由規(guī)則都會有自己的 name,為啥要命名?最直接的理由是為了唯一標(biāo)識每條規(guī)則。除了此因素外,我們可以在開發(fā)過程中選擇使用哪條規(guī)則,有了 name,想找出某條規(guī)則就好辦了,就好比你上學(xué)的時候,老師點名,要么點姓名,要么點學(xué)號。
基于 Attribute 的路由規(guī)則也可以命名的,例如。
[Route("hello/[controller]/[action]", Name = "prv")]這樣就把它命名為 prv 了,你還可以這樣寫。
[Route("hello/[controller]/[action]", Name = "[controller]_[action]")]這樣也可以用 Controller 和 Action 的名字生成一個唯一的名字,比如 Something_SayHi。但是這種方法太動態(tài)了,好像不那么好操控,還是用一個固定的名字好一點。
要在開發(fā)的時候選擇使用指定的 URL 路由,需要在 Razor 頁中添加 Tag Helper,標(biāo)記幫助類可以擴展 HTML 標(biāo)記的某些功能。在需要使用 tag helper 的頁面,或者統(tǒng)一在 _ViewImports.cshtml 頁中加入這些指令。
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers格式是這樣的:
<類型全路徑>, <程序集>類型寫在前面(包括 namespace 名),程序集名寫在后面,用逗號分隔。這里用星號(*)是最爽的,它是通配符,表示引入所有 tag helper 類型。這樣快捷,一行代碼了事。
然后在 HTML 中你這樣寫。
<form method="post"
? ? ? ? ? asp-route="edit_post">
? ? ? ? <div class="form-group">
? ? ? ? ? ? <label asp-for="Name"></label>
? ? ? ? ? ? <input asp-for="Name" class="form-control"/>
? ? ? ? ? ? <span asp-validation-for="Name" class="text-danger"></span>
? ? ? ? </div>
? ? ? ? <div class="form-group">
? ? ? ? ? ? <label asp-for="Age"></label>
? ? ? ? ? ? <input asp-for="Age" class="form-control"/>
? ? ? ? ? ? <span asp-validation-for="Age" class="text-danger"></span>
? ? ? ? </div>
? ? ? ? <input asp-for="ID"/>
? ? ? ? <button type="submit" class="btn btn-dark">提交</button>
? ? </form>
其他代碼你不用看了,只看這一句就夠了:
asp-route="edit_post"它的意思就是使用我剛剛定義的那條規(guī)則。
route.MapRoute("edit_post", "{controller}-{action}");所以,在運行后就會生成這樣的 HTML。
<form method="post" action="/Students-Editdata"><div class="form-group">此處省略 1650 個字</form>因為我定義的規(guī)則是 {controller}-{action}的形式,所以,Controller 是 Students,Action 是 Editdata,連起來就是 Students-Editdata。
那么,這里它為什么能識別出 controller 和 action 的值呢,你看看我的代碼就知道了。
public class StudentsController : Controller
? ? {
? ? ? ? readonly StudentDBContext m_context;
? ? ? ? // 接收依賴注入
? ? ? ? public StudentsController(StudentDBContext c)
? ? ? ? {
? ? ? ? ? ? m_context = c;
? ? ? ? }
? ? ? ? public IActionResult List()
? ? ? ? {
? ? ? ? ? ? var q = from s in m_context.Students
? ? ? ? ? ? ? ? ? ? orderby s.ID
? ? ? ? ? ? ? ? ? ? select s;
? ? ? ? ? ? return View(q.ToList());
? ? ? ? }
? ? ? ? /***************************************************/
? ? ? ? // 以下方法用于編輯頁
? ? ? ? [HttpGet]
? ? ? ? public IActionResult Editdata([FromRoute(Name = "sid")] int id)
? ? ? ? {
? ? ? ? ? ? var q = from s in m_context.Students
? ? ? ? ? ? ? ? ? ? where id == s.ID
? ? ? ? ? ? ? ? ? ? select s;
? ? ? ? ? ? Student stu = q.FirstOrDefault();
? ? ? ? ? ? if(stu == null)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? return Content("在地球上找不到此學(xué)員。");
? ? ? ? ? ? }
? ? ? ? ? ? return View(stu);
? ? ? ? }
? ? ? ? [HttpPost]
? ? ? ? public IActionResult Editdata(Student s)
? ? ? ? {
? ? ? ? ? ? if (ModelState.IsValid == false)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? return View(s);
? ? ? ? ? ? }
? ? ? ? ? ? m_context.Students.Update(s);
? ? ? ? ? ? m_context.SaveChanges();
? ? ? ? ? ? return RedirectToAction(nameof(List));
? ? ? ? }
? ? }
定義了 Editdata 方法的重載,一個用于 get 請求,一個用于 post 請求,form 是以 post 方式提交,因此它能自動識別出 controller 和 action 的名字。
那萬一,如果不是同名的呢,好辦。你用 asp-route-<value> 來指定各個參數(shù)的值。比如這樣
<form method="post"asp-route="edit_post"asp-route-controller="Demo"asp-route-action="Runwork"asp-route-sid="1">在 asp-route- 后面直接跟上路由規(guī)則參數(shù)的名稱就可以了。
?
有一點要注意,asp-route 與 asp-controller、asp-action是會沖突的,如果你用了這兩個標(biāo)記,就不能用 asp-route 標(biāo)記了,當(dāng)然 asp-route-xxx 是可以用的。
好了,今天的內(nèi)容就扯到這兒了,順便把示例的代碼也傳上來,以供伙伴們娛樂。
https://files.cnblogs.com/files/tcjiaan/NamedRouteSample.zip
原文地址:https://www.cnblogs.com/tcjiaan/p/8439178.html
.NET社區(qū)新聞,深度好文,歡迎訪問公眾號文章匯總 http://www.csharpkit.com
總結(jié)
以上是生活随笔為你收集整理的【ASP.NET Core】给路由规则命名有何用处的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 快速序列化组件MessagePack介绍
- 下一篇: .NET/.NET Core中更清晰的堆