简体   繁体   English

ASP.NET Core 2.2中的端点路由不起作用

[英]Endpoint Routing in ASP.NET Core 2.2 is Not Working

Update (2) 更新(2)

@poke seems to have figured it out and it looks to be an issue with endpoint routing itself favoring the {*url} if there's perceived ambiguity with other higher routes. @poke似乎已经解决了这个问题,并且如果端点路由本身支持{*url}似乎与其他更高的路由存在歧义,这似乎是一个问题。

Update (1) 更新(1)

@poke commented that I had a typo on the {*url} route where the t in controller was missing. @poke评论说我在{*url}路线上有错字,而控制器中的t丢失了。 After fixing that the {*url} route started working and the DefaultController.Gone action was working. 修复{*url}路由开始起作用并且DefaultController.Gone操作起作用之后。

BUT! 但! Now weird behavior is starting to crop up again. 现在,奇怪的行为开始再次出现。 After the {*url} was fixed, navigating to /settings which is supposed to match the {controller}/{action} route fails and falls back to the {*url} route. 修复{*url}后,导航至/settings应该与{controller}/{action}路由匹配的{controller}/{action}失败,并退回到{*url}路由。

If I remove the {*url} route from the registrations then /settings works again. 如果我从注册中删除了{*url}路由,那么/settings再次起作用。 The {action} route continues to not work. {action}路由继续不起作用。

Original 原版的

Please forgive the length of the question, but I am trying to offer as much information as possible. 请原谅问题的长度,但我正在尝试提供尽可能多的信息。

I am working on an ASP.NET Core 2.2 blogging app for myself, and I'm having inexplicable problems getting routing to work. 我正在为自己开发ASP.NET Core 2.2博客应用程序,但是在路由工作时遇到了莫名其妙的问题。 After spending half the day yelling at my screens, I decided to take a step back and start a new project that was completely isolated. 花了半天的时间在银幕上大喊大叫后,我决定退后一步,开始一个完全孤立的新项目。 Somehow the problems persisted in the new project. 问题在新项目中仍然存在。 I've stripped it down pretty much to a starved skeleton and I still can't get the routes to work. 我已经将它几乎剥落成饥饿的骨架,但我仍然无法找到工作的路线。 The routes I'm trying to set up are: 我要设置的路线是:

settings/{controller}/{id:int}/{action} - works
settings/{controller}/{action} - works
blog/{*slug} - works
blog/{skip:int?} - works
{controller}/{action} - works
{action} - doesn't work
{*url} - doesn't work

Specifically, I'm having problems with the last two routes. 具体来说,我在最后两条路线上遇到了问题。

The {action} route is not generating for simple actions like DefaultController.About even though it has no constraints, all it has is defaults for PostsController.List because I want a list of posts to be shown for the root URL. {action}路由不会为诸如DefaultController.About类的简单操作生成。关于它,尽管它没有任何约束,但它所具有的只是PostsController.List默认值,因为我希望显示针对根URL的帖子列表。

The {*url} just doesn't seem to work at all. {*url}似乎根本不起作用。 I want to use it as my final fallback and it's defaulted to DefaultController.Gone , but if I just bash on the keyboard for some nonsense URL all I get is a 404 error. 我想将其用作我的最终后备,默认情况下将其设置为DefaultController.Gone ,但是如果我只是在键盘上猛击一些废话URL,那么我得到的只是一个404错误。

I feel that the issue is with the DefaultController since both the About and Gone actions are in it and neither one seems to be working, but I just can't seem to figure out how. 我觉得问题出在DefaultController因为其中同时包含AboutGone动作,而且似乎都无法正常工作,但是我似乎无法弄清楚该怎么做。 It literally does nothing but renders views, just like the other controllers. 就像其他控制器一样,它实际上不执行任何操作,而是呈现视图。

Below is the code of the stripped down project. 下面是精简项目的代码。 I'd really appreciate it if someone can spin it up and tell me where I'm failing because I certainly can't seem to figure it. 如果有人可以将其旋转并告诉我失败的原因,我将非常感激,因为我似乎无法弄清楚它。

Program.cs Program.cs中

public sealed class Program {
    public static async Task Main(
        string[] args) => await WebHost.CreateDefaultBuilder(args)
                                       .UseStartup<Startup>()
                                       .Build()
                                       .RunAsync();
}

Startup.cs Startup.cs

public class Startup {
    public void ConfigureServices(
        IServiceCollection services) {
        services.AddMvc()
                .SetCompatibilityVersion(CompatibilityVersion.Latest);
    }

    public void Configure(
        IApplicationBuilder app) {
        app.UseMvc(
            r => {
                //  /settings/{controller}/{id}/{action}
                r.MapRoute("600", "settings/{controller}/{id:int}/{action}", null, new {
                    controller = "Categories|Tags"
                });

                //  /settings/{controller}/{action}
                r.MapRoute("500", "settings/{controller}/{action}", null, new {
                    controller = "Categories|Tags"
                });

                //  /blog/*
                r.MapRoute("400", "blog/{*slug}", new {
                    action = "Show",
                    controller = "Posts"
                });

                //  /blog/{skip}
                r.MapRoute("300", "blog/{skip:int?}", new {
                    action = "List",
                    controller = "Posts"
                });

                //  /{controller}/{action}
                r.MapRoute("200", "{controller}/{action=Default}", null, new {
                    controller = "Settings|Tools"
                });

                //  /{action}
                r.MapRoute("100", "{action}", new {
                    action = "List",
                    controller = "Posts"
                });

                //  /*
                r.MapRoute("-1", "{*url}", new {
                    action = "Gone",
                    conroller = "Default"
                });
            });
    }
}

CategoriesController.cs CategoriesController.cs

public sealed class CategoriesController :
    Controller {
    [HttpGet]
    public IActionResult Add() => Content("Category added");

    [HttpGet]
    public IActionResult Remove(
        int id) => Content($"Category {id} removed");
}

DefaultController.cs DefaultController.cs

public sealed class DefaultController :
    Controller {
    [HttpGet]
    public IActionResult About() => View();

    [HttpGet]
    public IActionResult Gone() => View();
}

About.cshtml (Default) About.cshtml(默认)

<h1>DEFAULT.ABOUT</h1>

Gone.cshtml (Default) Gone.cshtml(默认)

<h1>DEFAULT.GONE</h1>

PostsController.cs PostsController.cs

public sealed class PostsController :
    Controller {
    [HttpGet]
    public IActionResult List(
        int? skip) => View();

    [HttpGet]
    public IActionResult Show(
        string slug) => View();
}

List.cshtml (Posts) List.cshtml(帖子)

<h1>POSTS.LIST</h1>
<a asp-action="Show" asp-controller="Posts" asp-route-slug="test-test-test">Show a Post</a>

Show.cshtml (Posts) Show.cshtml(帖子)

<h1>POSTS.SHOW</h1>

SettingsController.cs SettingsController.cs

public sealed class SettingsController :
    Controller {
    [HttpGet]
    public IActionResult Default() => View();
}

Default.cshtml (Settings) Default.cshtml(设置)

<h1>SETTINGS.DEFAULT</h1>
<a asp-action="Add" asp-controller="Categories">Add a Category</a>
<br />
<a asp-action="Remove" asp-controller="Categories" asp-route-id="1">Remove a Category</a>
<hr />
<a asp-action="Add" asp-controller="Tags">Add a Tag</a>
<br />
<a asp-action="Remove" asp-controller="Tags" asp-route-id="1">Remove a Tag</a>

TagsController.cs TagsController.cs

public sealed class TagsController :
    Controller {
    [HttpGet]
    public IActionResult Add() => Content("Tag added");

    [HttpGet]
    public IActionResult Remove(
        int id) => Content($"Tag {id} removed");
}

ToolsController.cs ToolsController.cs

public sealed class ToolsController :
    Controller {
    [HttpGet]
    public IActionResult Default() => View();
}

Default.cshtml Default.cshtml

<h1>TOOLS.DEFAULT</h1>

_Layout.cshtml _Layout.cshtml

<!DOCTYPE html>
<html>
<head>
    <title>@ViewBag.Title</title>
</head>
<body>
    <a asp-action="List" asp-controller="Posts">Blog</a>
    <br />
    <a asp-action="Default" asp-controller="Tools">Tools</a>
    <br />
    <a asp-action="About" asp-controller="Default">About</a>
    <br />
    <a asp-action="Default" asp-controller="Settings">Settings</a>
    <br />
    @RenderBody()
</body>
</html>

{action} - doesn't work {action} -不起作用

This one doesn't work because it has to match an actual action. 此操作无效,因为它必须匹配实际操作。 So it works for /Show or /List since you are operating on the PostsController . 因此,由于您在PostsController上进行操作,因此它适用于/Show/List It also works for / since the action defaults to List . 由于action默认为List因此它也适用于/

{*url} - doesn't work {*url} -不起作用

This one will work if you set the default controller , instead of the conroller : 如果设置了默认此一的工夫controller ,而不是conroller

r.MapRoute("-1", "{*url}", new
{
    action = "Gone",
    controller = "Default"
});

<a asp-action="About" asp-controller="Default">About</a>

Note that this route will also not match because there is no route to that action. 请注意,此路由也将不匹配,因为没有该操作的路由。 The {controller}/{action} routes are constrained to the SettingsController and ToolsController , so the route won't match. {controller}/{action}路由被限制到SettingsControllerToolsController ,因此路由不匹配。 You will need to adjust the constraint or add another route for this to work. 您将需要调整约束条件或添加其他路线才能使其生效。

Btw. 顺便说一句。 as a general suggestion: As you probably noticed, managing this many route mapping gets quite complicated. 作为一般建议:您可能已经注意到,管理这么多的路由映射变得相当复杂。 It's often easier to just use attribute routing with explicit routes. 仅将属性路由与显式路由一起使用通常会更容易。 You could also mix those with template based routing to get the best of both worlds. 您也可以将它们与基于模板的路由结合使用,以充分利用两者的优势。


Weirdly /settings which is supposed to match the {controller}/{action} route is now failing and falling back to the {*url} route. 奇怪的是,应该与{controller}/{action}路由匹配的/settings现在失败了,并退回到了{*url}路由。 If I remove the {*url} route from the registrations then /settings works again. 如果我从注册中删除了{*url}路由,那么/settings再次起作用。

That appears to be a side effect from comining the settings/{controller}/{action} and the {controller}/{action=Default} routes. 合并settings/{controller}/{action}{controller}/{action=Default}路由似乎是一个副作用。

I've been debugging through that now for a bit and it seems that this is a bug with endpoint routing, which favors the catch all route although it is being registered later. 我已经进行了一段时间的调试,这似乎是端点路由的一个错误,尽管以后要注册,但它倾向于捕获所有路由。

Unfortunately, endpoint routing in ASP.NET Core 2.2 is known to break on a few special cases which is why it is being revamped for 3.0 which will hopefully resolve all issues. 不幸的是,已知ASP.NET Core 2.2中的终结点路由会在一些特殊情况下中断,这就是为什么将其修改为3.0,从而有望解决所有问题的原因。 That being said, I've opened an issue about this particular problem and reported my findings. 话虽如此,我已经打开了一个有关此特定问题的问题并报告了我的发现。 Maybe there's a simple solution for this. 也许有一个简单的解决方案。

One easy workaround would be to change the settings/{controller}/{action} route template to use a prefix other than settings , so that there is no longer an ambiguity. 一种简单的解决方法是将settings/{controller}/{action}路由模板更改为使用settings以外的前缀,这样就不再存在歧义。 That appears to fix the issues. 看来可以解决问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 AuthorizeAttribute 不适用于 ASP.NET Core 3.1 中的端点路由 - AuthorizeAttribute not working with Endpoint Routing in ASP.NET Core 3.1 在 ASP.Net Core 2.2 MVC 中使用 Endpoint-Routing 时如何正确覆盖 IUrlHelper? - How top correctly override the IUrlHelper while using Endpoint-Routing in ASP.Net Core 2.2 MVC? Asp.Net Core 端点路由 - Asp.Net Core Endpoint routing ASP.NET Core 2.2身份验证不起作用 - ASP.NET Core 2.2 Authentication not working Asp.NET 核心 2.2:Swagger 端点特定安全定义 - Asp.NET Core 2.2: Swagger endpoint specific security definition Asp.net Core 2.2 MVC 5路由可在View中使用更多子文件夹 - Asp.net core 2.2 mvc 5 routing for more subfolders in Views ASP.NET Core 3.0 Endpoint Routing 不工作并且找不到 404 - ASP.NET Core 3.0 Endpoint Routing not working and getting 404 not found 从 MVC 迁移到 ASP.NET Core 3.1 中的端点路由时,具有角色的 AuthorizeAttribute 不起作用 - AuthorizeAttribute with Roles not working when migrating from MVC to Endpoint Routing in ASP.NET Core 3.1 ASP.NET Core 3 MVC端点路由和按路由定位 - ASP.NET Core 3 MVC endpoint routing and localization by route 视图中的ASP.NET Core端点路由链接生成 - ASP.NET Core Endpoint Routing Link Generation in Views
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM