如何全局配置 ASP.NET Core 6+ API 路由,使其在从控制器名称生成时格式化为短横线格式?

问题描述 投票:0回答:2

我有一个 ASP.NET Core 6 Web API 项目。一些端点与名称由多个单词组成的控制器相关,因此按照 .NET 中的约定采用 PascalCase 格式。假设我有一个

PackageGroupsController
。我希望它的路线是
/package-groups
而不是默认的
/PackageGroups
并且我不想为每个控制器指定硬编码路线。我怎样才能使用全局配置或其他东西来实现这一点?

c# rest asp.net-core .net-core
2个回答
11
投票

AddControllers
允许您自定义所使用的约定,您可以尝试使用带有
RouteTokenTransformerConvention
的约定。比如:

builder.Services.AddControllers(opts => 
    opts.Conventions.Add(new RouteTokenTransformerConvention(new ToKebabParameterTransformer())));

public class ToKebabParameterTransformer : IOutboundParameterTransformer
{
    public string TransformOutbound(object? value) => value != null 
        ? Regex.Replace(value.ToString(), "([a-z])([A-Z])", "$1-$2").ToLower() // to kebab 
        : null; 
}

0
投票

想分享我的实现,并对 Guru Stron 的答案稍加修改。

builder.Services.AddControllers(options => 
    options.Conventions.Add(new RouteTokenTransformerConvention(new ToKebabParameterTransformer())));

public partial class ToKebabParameterTransformer : IOutboundParameterTransformer
{
    [GeneratedRegex("([a-z])([A-Z])")]
    public static partial Regex KebabCaseGeneratedRegex();

    public string? TransformOutbound(object? value)
    {
        if (value is null || value is not string) return null;
        return KebabCaseGeneratedRegex().Replace((string)value, "$1-$2").ToLower();
    }
}

用法与原答案相同,修改部分如下:

  • 解决 “使用 'GeneeratedRegexAttribute' 在编译时生成正则表达式实现。(
    SYSLIB1045
    )”
    • 此警告是在 .NET 7 中引入的,可以通过在
      GeneratedRegex
      属性中指定模式来解决
    • 这要求变压器类为
      partial class
  • 使用 return Early 模式和
    is
    运算符来处理 null 而不是字符串值

我还发现从

ControllerContext
检索到的控制器名称没有被转换,因此必须单独进行转换,类似于下面:

[Route("[controller]")]
public partial class SomeKebabCaseController() : ControllerBase
{
    // Included only for demonstration purpose, this should converted to be a utility class or similar to make it reusable
    [GeneratedRegex("([a-z])([A-Z])")]
    public static partial Regex KebabCaseGeneratedRegex();

    [HttpGet]
    public IActionResult ControllerName() {
        var controllerName = ControllerContext.RouteData.Values["controller"]!.ToString()!;
        var formattedControllerName = KebabCaseGeneratedRegex().Replace((string)controllerName, "$1-$2").ToLower();
        return Ok(formattedControllerName);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.