【ASP.NET Core】MVC控制器的各種自定義:應用程式約定的介面與模型

2022-11-13 21:04:08

從本篇起,老週會連發N篇水文,總結一下在 MVC 專案中控制器的各種自定義設定。

本文內容相對輕鬆,重點討論一下 MVC 專案中的各種約定介面。畢竟你要對控制器做各種自定義時,多數情況會涉及到約定介面。約定介面的結構都差不多,均包含一個 Apply 方法,實現類需要通過這個方法修改關聯的模型設定。

這些約定介面是按層次來定義的,下面咱們來扒一下。

a、IApplicationModelConvention:此介面可控制的面最廣,屬於應用程式層面。它對應的模型類是 ApplicationModel。該類有個重要屬性—— Controllers,通過它你能獲取到當前應用程式已發現和識別的所有控制器資訊。每個控制器也有自己的模型類:ControllerModel。

b、IControllerModelConvention:此介面只應用於控制器層面,而不是整個應用程式。對應的模型類就是上面提到過的 ControllerModel。ControllerType屬性可以獲取控制器類的 Type 資訊,而 ControllerName 屬性最有用,因為可以改變預設的控制器命名。Actions 屬性返回此控制器中所有操作方法(Action)列表。

c、IActionModelConvention:這個介面只應用於操作方法。對應的模型類是 ActionModel。通過 ActionName 屬性可以修改操作方法的名稱。當然,操作方法的名稱可以用 ActionNameAttribute 特性類來定義。

d、IParameterModelConvention:此介面只能自定義操作方法的引數,對應的模型類是 ParameterModel。

e、IPageApplicationModelConvention、IPageHandlerModelConvention、IPageRouteModelConvention:這些介面是用在 Razor Pages 上的,也可以實現一些自定義行為。

按照需求實現對應的介面。對於應用程式層面的設定,將實現相關約定介面的類範例新增到 MvcOptions.Conventions 集合中。如果實現了 IControllerModelConvention 介面的類範例新增到 Conventions 集合中,那麼它會被應用到所有控制器上。如果只想用到特定的控制器上,應將實現類定義為特性類,然後應用程式目標控制器上。

好了,理論的東西老周就不長篇大吹了,畢竟也不是老周的特長。只要你瞭解以上各介面和相關模型類,基本上就能運用了。

下面咱們做個很實在的演示:寫一個特性類(ControllerNameAttribute),用來給控制器設定名稱。既然是針對控制器的,約定介面應選擇 IControllerModelConvention。實現程式碼如下:

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public class ControllerNameAttribute : Attribute, IControllerModelConvention
{
    // 私有欄位
    private readonly string _name;

    // 建構函式
    public ControllerNameAttribute(string name)
    {
        // 自定義的控制器名稱就是這樣傳遞的
        _name = name;
    }

    // 這是實現介面的方法
    public void Apply(ControllerModel controller)
    {
        // 修改控制器名稱
        controller.ControllerName = _name;
    }
}

這個類的邏輯很䜭智,通過建構函式的引數來傳遞自定義的控制器名稱,然後存在 _name 私有欄位中。在Apply方法中,把 _name 欄位賦值給 ControllerName屬性,就完成控制器名稱的修改了。

這個特性類用於控制器,它是一個類,所以 AttributeTargets 選用 Class。咱們建立一個新控制器,然後用 ControllerNameAttribute 來設定控制器的名稱。

    [ControllerName("XinWen")]
    public class NewsController : Controller
    {
        [ActionName("catelogs")]
        public IActionResult GetCates()
        {
            return Ok(new string[]
            {
                "頭條新聞",
                "體育新聞",
                "內娛醜聞",
                "炒股趣聞",
                "生活百事",
                "名場面集錦",
                "都市傳說",
                "人品觀察報"
            });
        }
    }

預設的時候,控制器名稱與類名相同(有 Controller 字尾的會去掉),即 News。咱們應用剛定義的特性類 ControllerNameAttribute 將控制器命名為 XinWen。操作方法 GetCates 也被重命為 catelogs。

ActionNameAttribute 是 .NET 內建已有的型別,我們可以直接用。ControllerNameAttribute 非內建,所以咱們要自己來實現。

 

下面程式碼初始化應用程式。

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
var app = builder.Build();

app.MapControllerRoute("app", "{controller}/{action}");

app.Run();

 

程式執行後,存取 /xinwen/catelogs,就能看到結果了。