【ASP.NET Core】MVC控制器的各種自定義:修改參數的名稱

在上一篇中,老周演示了通過實現約定接口的方式自定義控制器的名稱。

至於說自定義操作方法的名稱,就很簡單了,因爲有內置的特性類可以用。看看下面的例子。

    [Route("[controller]/[action]")]
    public class StockController : Controller
    {
        [ActionName("OutGoing"), HttpGet("{q?}")]
        public string Sendout(int q) => $"今天發出{q}筆訂單";
    }

上述代碼中,本來操作方法的名稱是“Sendout”,但應用了 ActionName 特性後,就變成“OutGoing”了。訪問 /stock/outgoing/12 試試看。

 

 如何?簡單吧。可是有大夥伴會說,那我用實現約定接口的方式能實現嗎?能,擴展的是 IActionModelConvention 接口,修改 ActionModel 實例的 ActionName 屬性就可以了。請參考下面代碼:

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class MyActionNameAttribute : Attribute, IActionModelConvention
{
    private readonly string _actionName;

    public MyActionNameAttribute(string Name)
    {
       _actionName = Name;
    }

    public void Apply(ActionModel action)
    {
        action.ActionName = _actionName;
    }
}

然後,咱們用自己定義的這個特性類替換 ActionName 特性。

    [Route("[controller]/[action]")]
    public class StockController : Controller
    {
        [MyActionName("OutGoing"), HttpGet("{q?}")]
        public string Sendout(int q) => $"今天發出{q}筆訂單";
    }

效果是一樣的喲。

------------------------------------------------------------------ 銀河分隔線 ----------------------------------------------------------------

控制器和操作方法的自定義名稱好弄,但,方法參數的名稱就不好弄了。有大夥伴就不樂意了,我直接按思路套代碼不就行了嗎?擴展下 IParameterModelConvention 接口,然後設置 ParameterModel.ParameterName 屬性不就完事了嗎?

是的,夢境總是那麼美好,咱們不妨試試。

    [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)]
    public class MyParameterAttribute : Attribute, IParameterModelConvention
    {
        private readonly string _name;

        public MyParameterAttribute(string name)
        {
            _name = name;
        }

        public void Apply(ParameterModel parameter)
        {
            parameter.ParameterName = _name;
        }
    }

接着,套在控制器的操作方法上。

public class TestController : Controller
{
    [HttpGet("test/get")]
    public int GetNumber([MyParameter("num")]int xx) => xx * 5;
}

試試看,訪問 /test/get?num=5。結果……

 

 WTF,這是咋回事呢?不知道夥伴們有沒有看過老周曾寫過模型綁定的水文。其實這裏我們不需要對模型綁定有多深的瞭解,但我們得知道,對於操作方法的參數來說,是存在模型綁定這一過程的。這就導致不能修改一下參數名就完事了,ModelBinder 認的是參數的數據類型,而不是 ApplicationModel 中的信息。這裏頭牽涉的東西太多了,你無法任性地擴展一兩個接口就能完事的。但也不是沒有辦法,不用寫擴展,有個現成的特性類也能給參數設置別名。

   [HttpGet("test/get")]
   public int GetNumber([ModelBinder(Name = "num")]int xx) => xx * 5;

使用 ModelBinder特性,然後改一下 Name 屬性就好了。咱們再試試。

 

 怎麼樣,有效果吧。

可你又說了,我要是堅持要通過約定接口來擴展,那有法子乎?有,原理一樣,改 ModelBinder 的名字。

    [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)]
    public class MyParameterAttribute : Attribute, IParameterModelConvention
    {
        private readonly string _name;

        public MyParameterAttribute(string name)
        {
            _name = name;
        }

        public void Apply(ParameterModel parameter)
        {
            // 注意,BindingInfo 屬性可能會爲null
            parameter.BindingInfo ??= new BindingInfo();
            // 修改模型名稱
            parameter.BindingInfo.BinderModelName = _name;
        }
    }

原理就是設置 BindingInfo 類的 BinderModelName 屬性。

再試試看。

[HttpGet("test/get")]
public int GetNumber([MyParameter("num")]int xx) => xx * 5;

 

總算有滿意的結果了。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章