【asp.net core 系列】2 控制器與路由的恩怨情仇

月影西下發表於2020-06-02

0. 前言

在上一篇文章中,我們初步介紹了asp.net core,以及如何建立一個mvc專案。從這一篇開始,我將為大家展示asp.net core 的各種內容,並且嘗試帶領大家來挖掘其中的內在邏輯。

當然,那是以後的事情。這一篇將通過自定義一個控制器來為大家介紹asp.net core mvc 中控制器和路由的相關知識。

1. 控制器

先在Controllers目錄下新增一個類,名叫:

public class DemoController
{
    public string Index()
    {
        return "你好";
    }
}

訪問地址:

http://localhost:5006/demo/index

如果不出意外的話,你應該能看到網頁上的"你好"兩個字。

再新建一個類:

using Microsoft.AspNetCore.Mvc;
public class NoContrl : Controller
{
    public IActionResult Index()
    {
        return Content("Test");
    }
}

結合兩個不常規的控制器類,讓我們初窺asp.net core MVC是如何識別控制器的。這正是我之前說的,約定優於配置最好的體現。這個哲學最早也是為MVC提出來的,後來被.net framework引申到各個方面。

asp.net core mvc識別控制器,會在專案中發現 以Controller結尾的公開類或者繼承自Controller的公開類,並將這些類標記為控制器。當接到使用者或者介面轉交的請求時,程式從請求路徑中解析出控制器名稱,然後尋找 <控制器>Controller 或者 <控制器> : Controller 的類。

在預設情況下,一個訪問URL會在程式中解析成如下格式:

http://<HOST>:<PORT>/<Controller>/<Action>[其他引數]

在上文中,我們知道了控制器的解析規則,那麼現在看一下Action的解析規則:

在DemoController中新增如下方法:

public int TestInt()
{
    return 10;
}

public object TestObject()
{
    return new
    {
        Name = "TestObject",
        Age = 1
    };
}

public string TestPublic()
{
    return "成功訪問 TestPublic";
}

    protected string TestProtect()
{
    return "成功訪問 TestProtect";
}

private string TestPrivate()
{
    return "成功訪問 TestPrivate";
}

重新啟動,後依次訪問如下地址:

http://localhost:5006/Demo/TestInt
http://localhost:5006/Demo/TestObject
http://localhost:5006/Demo/TestPublic
http://localhost:5006/Demo/TestProtect
http://localhost:5006/Demo/TestPrivate

然後可以看到,TestInt、TestObject以及TestPublic均能正常訪問,但TestProtect和TestPrivate都提示找不到網頁或無法訪問。

可以看到,對於程式而言,Action就是控制器類裡的公開類方法,與方法的返回值無關。也就是說,程式會找到 XXXController 或者名為XXX但繼承了Controller的類作為XXX的控制器,然後繼續在這個類裡尋找到Action,如果沒有找到就會返回404的請求。

2. 路由

在第一節中,我們介紹了一下asp.net core mvc如何尋找控制器和Action,那這一節將介紹程式如何從請求連結中解析出控制器和Action的名稱,也就是路由對映。

路由(Routing)負責匹配傳入的HTTP請求,然後將這些請求傳送給應用的可執行終結點。終結點是應用的可執行請求處理程式碼單元,也就是我們控制器裡的方法(Action)。

2.1 路由的配置

對於所有的asp.net core模板都包括生成在程式碼中的路由。通常,我們要求路由在Startup.Configure方法中進行配置。

注意,Startup類裡有且只有一個Configure方法,不能出現其過載版本。

該方法的宣告一般情況如下:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env);

如果想要設定路由,需要先註明專案啟用路由:

app.UseRouting();

然後使用如下方法配置路由:

app.UseEndpoints(endpoints =>
{
    // 配置路由
});

通常對於mvc專案而言,我們一般使用如下方式配置路由:

endpoints.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

這行程式碼的意思是:建立一個名字為 default 的對映控制器的路由,對映規則為 {controller}/{action}/{id?},也就是第一個為控制器,第二個為Action,第三個是ID,其中ID可以不存在,當Action無法從請求地址中解析出來時預設為Index,控制器預設為Home。

通過這個解析,我們可以得知 我們之前訪問的

http://localhost:5000/

是哪個控制器裡的什麼方法來處理了——HomeController.Index。

那麼我們修改一下HomeController.Index來驗證一下,我們理解是否有誤:

public IActionResult Index()
{
    return View();
}
//  修改為
public IActionResult Index()
{
    return Content("測試");
}

重新執行程式,訪問

http://localhost:5000/

然後看到頁面出現:測試字樣,可以看到路由系統自動為我們補全了控制器名和action名。如果方法中出現引數,則自動按照引數名1=值1&引數名2=值2這種形式檢視引數。Id為特殊的,會自動按照目錄其對映。所以:

http://localhost:5000/控制器1/方法1/id值
http://localhost:5000/控制器1/方法1?id=id值

是一個請求連結。

2.2 新增路由配置

那麼,我們回過頭來看一下宣告路由的方法:

public static ControllerActionEndpointConventionBuilder MapControllerRoute(this IEndpointRouteBuilder endpoints, string name, string pattern, object defaults = null, object constraints = null, object dataTokens = null);

預設情況下,我們不會設定 defaults、constraints、dataTokens,這三個引數都有含義,這裡不對後兩個做介紹,簡單介紹一下第一個:

在路由配置的方法裡,新增以下內容:

endpoints.MapControllerRoute(
                    name : "test",
                    pattern: "DemoTest/{action=Index}/{id?}",
                    defaults : new 
                    {
                        Controller = "Demo",

                    });

至此,我們沒有建立名為DemoTest的控制器,但是我們在訪問:

http://localhost:5006/DemoTest

仍然能得到響應,而且控制器被解析為Demo。

這就是defaults的意義,路由在解析的時候,系統會把defaults中的值自動填充到路由連線中沒有設定的值裡。

當我們設定多個路由的時候,路由系統會優先嚐試匹配最容易解析的配置。比如說,當我們訪問:

http://localhost:5000/DemoTest/

的時候,路由系統會優先從名為test的配置表中解析,只有當無法從這裡找到時才會從其他路由中解析。

3. 總結

這一篇我們簡單介紹了控制器與路由對映,可以訪問我們自己新增的路由。在開發中,通常情況下,建立的控制器都是以Controller結尾並繼承Controller類。這是因為Controller類有很多有用的屬性和方法供我們使用,以Controller結尾是為了統一規則,可以讓我們一眼看出哪些是控制器。

更多內容煩請關注我的部落格《高先生小屋》

file

相關文章