ASP.NET CORE MVC 實現減號分隔(Kebab case)樣式的 URL

ASP.NET CORE MVC 中,默認的 Route 模板是: /{controller}/{action}  。咱們能夠經過開啓 URL 小寫轉換將 URL 變爲小寫,但此方式在 Controller 或者 Action 爲一個詞組時,生成的 URL 並不友好。假設咱們有 UserController 和 AddUser 方法,則框架生成的 URL 多是: /User/AddUser ,在開啓小寫轉換的狀況下多是下面的結果: /user/adduser 。包含大寫字符的 URL 並無問題,可是小寫的 URL 更加常規,而徹底轉換小寫形成的問題就是 URL 的可讀性不好。本文將提供一些代碼,幫助框架生成減號分隔樣式的 URL ,當應用了這些代碼之後,生成的 URL 相似這樣: /user/add-user 。 微軟爲咱們提供了 RouteAttribute ,能夠對 Controller 或者 Action 進行標記,以達到自定義訪問路徑的目的。這種方式很是強大,但在項目較大的狀況下使用起來有些繁雜。畢竟手工對每個 Controller 和 Action 進行標記也有不小的工做量。 ASP.NET CORE MVC 框架中定義了一個 IControllerModelConvention 接口,咱們能夠實現該接口在運行時爲 Action 附加一個 Route 模型。在項目中新建 DashedRoutingConvention 類文件,代碼以下:html

    public class DashedRoutingConvention : IControllerModelConvention
    {
        public void Apply(ControllerModel controller)
        {
            var hasRouteAttributes = controller.Selectors.Any(selector =>
                selector.AttributeRouteModel != null);
            if (hasRouteAttributes)
            {
                // This controller manually defined some routes, so treat this 
                // as an override and not apply the convention here.
                return;
            }

            foreach (var controllerAction in controller.Actions)
            {
                foreach (var selector in controllerAction.Selectors.Where(x => x.AttributeRouteModel == null))
                {
                    var parts = new List<string>();
                    foreach (var attr in controller.Attributes)
                    {
                        if (attr is AreaAttribute area)
                        {
                            parts.Add(area.RouteValue);
                        }
                    }

                    if (
                        parts.Count == 0
                        && controller.ControllerName == "Home"
                        && controllerAction.ActionName == "Index"
                    )
                    {
                        continue;
                    }

                    parts.Add(PascalToKebabCase(controller.ControllerName));

                    if (controllerAction.ActionName != "Index")
                    {
                        parts.Add(PascalToKebabCase(controllerAction.ActionName));
                    }

                    selector.AttributeRouteModel = new AttributeRouteModel
                    {
                        Template = string.Join("/", parts)
                    };
                }
            }
        }

        private static string PascalToKebabCase(string value)
        {
            if (string.IsNullOrEmpty(value))
            {
                return value;
            }

            return Regex.Replace(
                    value,
                    "(?<!^)([A-Z][a-z]|(?<=[a-z])[A-Z])",
                    "-$1",
                    RegexOptions.Compiled)
                .Trim()
                .ToLower();
        }
    }

以後,將 DashedRoutingConvention 在 Startup.cs 中註冊。c#

public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddMvc(options => options.Conventions.Add(new DashedRoutingConvention()));
}

 

至此,所有代碼完畢。 Notices:mvc

  1. 本代碼支持 Area ,並會對 Area 名稱也進行轉義。
  2. 本代碼使用自定義路由的方式實現功能,因此可能對預約義路由有影響。
  3. 更多與路由相關的信息可參見:https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/routing
  4. 本代碼參考了其餘代碼,詳見:https://stackoverflow.com/questions/40334515/automatically-generate-lowercase-dashed-routes-in-asp-net-core
  5. 碼農很忙受權中心已經啓用了本代碼,演示:https://passport.coderbusy.com/
相關文章
相關標籤/搜索