ASP.NET Core MVC 中的 [Controller] 和 [NonController]

weixin_34162629發表於2016-09-20

前言

我們知道,在 MVC 應用程式中,有一部分約定的內容。其中關於 Controller 的約定是這樣的。

  • 每個 Controller 類的名字以 Controller 結尾,並且放置在 Controllers 目錄中。
  • Controller 使用的檢視是在 Views 主目錄的一個子目錄中,這個子目錄是根據控制器名稱(後面減去Controller字尾)來命名的。

明白了以上約定之後,就來一起看看下面吧。

Controller VS NonController 中內建的約定

在 ASP.NET Core MVC 中已經統一了 MVC 和 Web Api 及 Web Pages, 他們具有相同的 Controller ,並且在 RC2 之後的版本中,ASP.NET Core MVC 支援了 POCO Controller,所以你在做一個 Web Api 的 Controller 的時候不需要再繼承自 Controller 基類。

POCO Controller 即 public 的,非抽象的,沒有任何繼承,不實現任何介面的 Controller 類,類似於 POCO Class,僅僅是以 Controller 結尾而已。

到這裡,有些同學可能會問了,在 POCO Controller 中如果我想獲取 HTTP 上下文的一些東西應該怎麼獲取呢? 嗯?。。。 這確實是個問題。。。。怎麼辦呢? 老實的繼承基類 Controller 吧,因為 Vnext 中的 POCO Controller 屬性注入已經被取消了。

如果你建立了一個 POCO Controller ,那麼他們的名字必須以 Controller 結尾,只有這樣他們才是一個有效的 Controller,不然的話,MVC 不會認為你這是一個 Controller 物件。即使你具有 Route 之類的標記也不可以。

所以,在建立一個 MVC Controller 的時候,就有兩個先決條件:

  • -- 繼承自 Controller 基類
  • -- 或者使用一個以 Controller 結尾的名字

下面是建立兩種 Controller 的一個 Web Api Controller示例:

[Route("api/[controller]")]
public class FooController : Controller
{
    [HttpGet]
    public string Get()
    {
        return "foo";
    }
}
 
[Route("api/[controller]")]
public class BarController
{
    [HttpGet]
    public string Get()
    {
        return "bar";
    }
}

現在有同學可能會問了,第一個既然已經繼承了 Controller 基類,再在定義 Controller 的時候還要加 Controller 字尾不是多此一舉麼?這樣寫可不可以呢?

[Route("api/[controller]")]
public class Foo : Controller
{
    [HttpGet]
    public string Get()
    {
        return "foo";
    }
}

好吧,這樣子也是正確的。為什麼呢?這是因為繼承的基類 Controller 已經被打上了 ControllerAttribute 的標記,打上了這個標記之後,在構建掃描的時候就會被認為是一個 Controller,也就是說整個繼承樹已經被認為是一個有效的 MVC Controller 了。

那麼,有同學又問了,這樣可不可以呢?

[Route("api/[controller]")]
public class Bar
{
    [HttpGet]
    public string Get()
    {
        return "bar";
    }
}

這樣子是不行的,因為這是一個 POCO Controller,沒有任何標記使 MVC 框架會認為這是一個有效的Controller,這個時候,如果 如果想讓框架認為這是一個有效的 Controller,可以通過新增 ControllerAttribute 的方式:

[Controller]
[Route("api/[controller]")]
public class Bar
{
    [HttpGet]
    public string Get()
    {
        return "bar";
    }
}

這個時候,MVC 框架就會認為這是個有效的 Controller 了。

同樣的,這樣的程式碼也是有效的,因為基類已經有了 ControllerAttribute 標記 :

[Controller]
public class ApiBase {}
 
[Route("api/[controller]")]
public class Bar : ApiBase
{
    [HttpGet]
    public string Get()
    {
        return "bar";
    }
}

還有一種可能性,就是當你有一個類,它恰好是以 Controller 結尾,但是實際上並不是一個 Controller 類怎麼辦呢? 這個時候,你就需要新增一個 NonControllerAttribute 標記,來宣告當前的類並不是一個 MVC 的 Controller 類,從而避免在構建的時候,框架會認錯。

[NonController]
public class DemoController
{
    // 非 action 程式碼
}

有一點需要注意的是,NonControllerAttribute 標記比 ControllerAttribute 具有更高的優先順序,所以當一個 Controller 同時具有這兩個標記的時候,會以 NonControllerAttribute 為準。

實際上,只要是整個 Controller 繼承樹中有一個 Controller 被標記為 NonControllerAttribute 的時候,整個繼承樹的 Controller 均會被認為是無效的 Controller 了。


本文地址:http://www.cnblogs.com/savorboard/p/dontnet-controller.html
作者部落格:Savorboard
歡迎轉載,請在明顯位置給出出處及連結

相關文章