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 类文件,代码如下:

   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 中注册。

public void ConfigureServices(IServiceCollection services)

{

    // Add framework services.

    services.AddMvc(options => options.Conventions.Add(new DashedRoutingConvention()));

}


至此,全部代码完毕。

Notices:

  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/


原文:https://www.coderbusy.com/archives/956.html


.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值