首页 > 解决方案 > 与包含可能位于中间的模式的任何 URL 匹配的 ASP.NET Core MVC 路由

问题描述

通常,MVC 路由是通过从 URL 的开头匹配模式来完成的,例如:

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(name: "MyRoute", pattern: "my.io/{*suffix}", defaults: new { controller = "MyController" });
});

但是,如果我想定义一个路由来捕获包含特定模式的任何请求,而不管它在 URL 路径中的哪个位置可以找到呢?像这样的东西:

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(name: "MyRoute", pattern: "{*prefix}/my.io/{*suffix}", defaults: new { controller = "MyController" });
});

正如您所希望看到的,我想捕获碰巧包含模式“/my.io/”的任何请求,无论它是否在 URL 的开头(通常是这样),在 URL 的中间,或在 URL 的末尾。在所有情况下,我还想捕获前缀和后缀,如果有的话。不用说,这些可能会发生不可预测的变化,这是我想使用通配符执行此操作的重要部分原因。

有没有办法使用 MVC 端点路由来做到这一点?

如果是,那么必须如何编写[Route()]属性MyController及其方法才能被路由子系统发现?

如果没有,我的替代方案是什么?

更新

经过一番研究,我确定我的问题与类似。不幸的是,那里没有明确的答案......

标签: c#asp.net-mvcroutes

解决方案


经过一些试验,我发现也许@panagiotis-kanavos 为我指明了正确的方向,毕竟!

虽然前缀和后缀确实可以大不相同(内容和长度),但我意识到长度仍然存在一些最终限制。

然后我定义了一些这样的路线:

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(name: "Api0", pattern: "my.io", defaults: new { controller = "MyController" });
    endpoints.MapControllerRoute(name: "Api1", pattern: "{part1}/my.io", defaults: new { controller = "MyController" });
    endpoints.MapControllerRoute(name: "Api2", pattern: "{part1}/{part2}/my.io", defaults: new { controller = "MyController" });
    endpoints.MapControllerRoute(name: "Api3", pattern: "{part1}/{part2}/{part3}/my.io", defaults: new { controller = "MyController" });
    endpoints.MapControllerRoute(name: "Api4", pattern: "{part1}/{part2}/{part3}/{part4}/my.io", defaults: new { controller = "MyController" });
    endpoints.MapControllerRoute(name: "Api5", pattern: "{part1}/{part2}/{part3}/{part4}/{part5}/my.io", defaults: new { controller = "MyController" });
    
    // ... and a couple more along the same vein.
});

接下来,我[Route]在 MyController 上定义了多个匹配的属性:

[Route("my.io")]
[Route("{part1}/my.io")]
[Route("{part1}/{part2}/my.io")]
[Route("{part1}/{part2}/{part3}/my.io")]
[Route("{part1}/{part2}/{part3}/{part4}/my.io")]
[Route("{part1}/{part2}/{part3}/{part4}/{part5}/my.io")]
...

my.io这成功地处理了包含最多 5 级前缀的任何 URL 。当然,这可以实际扩展到我需要的极限。 请参阅下面的重要编辑!

一旦我点击了我的操作方法,我就可以像这样简单地一次性读取整个后缀:

[Route("{*suffix}")]

在该方法中我需要做的唯一工作是将所有{partN}片段拼接在一起,我也可以直接从Request.Url.

重要编辑

看来我说话有点太早了。幸运的是,上述解决方案最多可用于 5 个段前缀。我确实注意到内存使用量略有增加,但除此之外一切正常。

但是一旦我添加了一个 6 段前缀,应用程序启动就开始明显滞后,并且内存使用量比以前翻了一番。

添加 7 段前缀会导致我的应用程序在启动时消耗超过 4 GB 的内存(通常应该低于 300 MB)并且服务请求变得非常慢。

似乎有一些指数级的恶作剧正在上演。不幸的是,这意味着这个解决方案比我最初认为的要有限得多。

重要编辑 2

经过进一步的实验,我确定不是endpoints.MapControllerRoute()调用缓慢和消耗内存的原因,而是[Route]控制器上的属性。当这些值超过 5 时,事情很快就会停止。我想知道这是为什么?

我怎样才能让它变得更好?

重要编辑 3

我在这个问题中向 ASP.NET Core 团队提出了这个问题。我们会看到它的去向。


推荐阅读