ASP.NET Core 路由属性 - ID 和连字符 slug 以连字符分隔

标签 asp.net asp.net-mvc routes asp.net-core asp.net-mvc-routing

我正在尝试通过 Route 属性为我的 Controller 操作之一配置以下 url 结构:

/products/12345-purest-green-widgets

这是我目前的路线:

[Route(@"/products/{id:int}-{slug:regex([[\w\-]]+)}")]
public ContentResult Show(int id, string slug)

这与预期路线不匹配,但确实匹配:

/products/12345-purest

并且还与一个单词后的尾随连字符匹配,一旦我添加其他任何内容,它就会不匹配。

有趣的是,如果我将字符串文字连字符(不是正则表达式的连字符)替换为/,它整体上工作正常:

[Route(@"/products/{id:int}/{slug:regex([[\w\-]]+)}")]
public ContentResult Show(int id, string slug)

匹配成功:

/products/12345/purest-green-widgets

所以它似乎被字符串文字连字符绊倒了。有什么想法吗?

最佳答案

如果深入挖掘,您会发现路由中间件正在贪婪地分割复杂的路由段,例如 {id:int}-{name:regex([[\w\-]]+)}甚至在应用路线约束之前。 (在启动中使用路由属性和路由表都会发生)

这意味着:

  • 网址如 products/123-foo ,路由匹配123作为 id 和 foo作为名字。然后它将应用约束,找到 123 的匹配项。是一个有效的 int 且 foo与正则表达式匹配。
  • 网址如 products/123-foo- ,路由匹配123作为 id 和 foo-作为名字。然后它将应用约束,再次找到匹配项。
  • 网址如 products/123-foo-bar ,路由匹配123-foo作为 id 和 bar作为名字。然后它将应用约束,但这一次它将失败,显示为 123-foo不是有效的整数!

如果您将参数拆分为不同的路线段(如 {id:int}/{name:regex([[\w\-]]+)} 所示),则不会出现此问题。 ,如/将按照您的预期正确分割参数。

如果您的路线确实需要具有该形状,那么我将在路线约束中使用单个参数。此参数将包装 id 和名称:

[Route(@"/products/{combined:regex(^[[\d]]+-[[\w\-]]+$)}")]

问题是您需要从该单个参数中手动提取 ID 和名称。

  • 您可以在 Controller 操作中手动执行此操作。对于一次性来说,这可能是可以接受的
  • 您可以创建一个 ActionFilter 并在执行操作之前将组合的路由参数拆分为操作参数(覆盖 OnActionExecuting )。这仍然很老套,特别是我的快速而肮脏的版本:

    public class SplitProductParametersActionFilter : ActionFilterAttribute
    {
        private static Regex combinedRegex = new Regex(@"^([\d]+)-([\w\-]+)$");
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            var combined = context.RouteData.Values["combined"].ToString();
            var match = combinedRegex.Match(combined);
            if (match.Success)
            {
                context.ActionArguments.Add("id", int.Parse(match.Groups[1].Value));
                context.ActionArguments.Add("name", match.Groups[2].Value);
            }
        }
    }
    
    [Route(@"/products/{combined:regex(^[[\d]]+-[[\w\-]]+$)}")]
    [SplitProductParametersActionFilter]
    public IActionResult Contact(int id, string name)
    {
    }
    
  • 您可以使用其模型绑定(bind)程序提供程序和参数的一些注释属性创建一个新的模型绑定(bind)程序。这可能是最干净的,因为它与上面的方法类似,但以模型绑定(bind)的预期方式扩展了 MVC,但是我还没有时间探索它:

    [Route(@"/products/{combined:regex(^[[\d]]+-[[\w\-]]+$)}")]
    public IActionResult Contact([FromUrlProduct("combined")]int id, [FromUrlProduct("combined")]string name)
    {
    }
    
<小时/>

为了调试路由约束,您可以将日志记录设置为调试,并且您应该在控制台中看到类似这样的消息(您可能需要使用 dotnet run 从控制台运行应用程序,而不是使用 VS 中的 ISS ):

dbug: Microsoft.AspNetCore.Routing.RouteConstraintMatcher[1]
      => RequestId:0HKVJG96H1RQE RequestPath:/products/1-foo-bar
      Route value '1-foo' with key 'id' did not match the constraint 'Microsoft.AspNetCore.Routing.Constraints.IntRouteConstraint'.

您还可以手动复制 int route constraint并在services.AddMvc()之后在启动中注册它与 services.Configure<RouteOptions>(opts => opts.ConstraintMap.Add("customint", typeof(CustomIntRouteConstraint)))

类似于 in this blog 所描述的方法也可能有助于调试。

关于ASP.NET Core 路由属性 - ID 和连字符 slug 以连字符分隔,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40009935/

相关文章:

c# - 在 Windows 10 中将应用程序注册到 URI 方案

asp.net - 如何重命名我的 asp.net 网页

javascript - 如何通过 ID 仅隐藏列表项中的图像?

asp.net-mvc - MVC : Use Display name as column header with CSVHelper

asp.net-mvc-4 - ASP.NET MVC4 ActionLink 路由查询字符串问题

c# - 无法在 asp.net core 的 startup.cs 文件中找到 Use.RunTimePageInfo() 方法

c# - 即使在使用 Identity ASP.NET MVC 框架关闭浏览器后,如何让用户保持登录状态?

c# - 如何使用 EF 在 ASP.NET MVC 中自动创建数据库和存储库?

jquery - 通过 AJAX 请求调用方法/路由时,重定向不起作用

javascript - Ember 路由设计。类似桌面的路线