ASP.NET CORE,Web API:没有路由与提供的值匹配

45

请注意:此问题是在2016年提出的。当时解决该问题的原始方法是更新Microsoft API版本包。当前,该问题再次出现,但原因不同。

原问题:


我在asp.net core(web api)中遇到路由问题。

我有这个控制器(简化版):

[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[Controller]")]
public class DocumentController : Controller
{

[HttpGet("{guid}", Name = "GetDocument")]
public IActionResult GetByGuid(string guid)
{
    var doc = DocumentDataProvider.Find(guid);
    if (doc == null)
        return NotFound();

    return new ObjectResult(doc) {StatusCode = 200};
}


[HttpPost]
public IActionResult Create([FromBody] Document doc)
{
    //... Creating Doc

    // Does not work   
    var val = CreatedAtRoute("GetDocument", new {guid = doc.Guid.ToString("N")}, document);

    // or this: 
    CreatedAtRoute("GetDocument", new { controller = "Document", guid = doc.Guid.ToString("N")}, document);
    // neither this
    var val = CreatedAtRoute("GetDocument", new { version = "1", controller = "Document", guid = doc.Guid.ToString("N")}, document);

    return val;
}
}
如果我调用Create,文档会被创建并且路由对象也被创建了,但是我收到了“没有与提供的值匹配的路由”错误并且返回了500状态。
我可以直接调用GetByGuid而没有任何问题。
我找不到任何适用于ASP.NET Core的调试帮助(例如任何现有的路由调试器)。
我会感激任何帮助!
编辑 看起来这可能是微软版本控制包中的一个bug..如果我定义固定路由/api/v1/[Controller],它就能工作了。
但对我来说,这不是一个解决方案。
15个回答

48

ASP.net core 3

出现这个问题的原因:

为了解决dotnet/aspnetcore#4849中提到的问题,ASP.NET Core MVC默认会从操作名称中删除后缀Async。自ASP.NET Core 3.0开始,此更改影响路由和链接生成。

查看更多:
ASP.NET Core 3.0-3.1 | Breaking Changes | 控制器操作名称中的异步后缀被删除

正如@Chris Martinez在Github Issue中所说:
.Net Core 3.0和使用CreatedAtRoute结果未找到匹配的路由值。#558:

更改的原因不是任意的; 它解决了另一个错误。如果您没有受到该错误的影响并想继续使用Async后缀,则可以重新启用它。

如何解决

重新启用它:

services.AddMvc(options =>
{
   options.SuppressAsyncSuffixInActionNames = false;
});

现在您应该传递createActionName参数,包括Async后缀,如下所示:

return CreatedAtAction("PostAsync", dto)


4
我在.NET 5.0上进行了测试,它能够正常工作,谢谢。 - yogihosting
4
非常感谢,这段代码在.NET 6上运行,只需进行小改动:services.AddControllersWithViews(options => { options.SuppressAsyncSuffixInActionNames = false; });其中,AddControllersWithViews方法用于将控制器和视图添加到服务中,options参数用于设置选项,SuppressAsyncSuffixInActionNames属性设置为false表示不要在操作名称中删除异步后缀。 - Ozan Yasin Dogan
1
谢谢,我将我的操作名称从GetByIdAsync()改为GetById() - undefined

30

我知道这篇文章是2017年的,但我刚刚遇到了同样的问题并来到了这里。看起来你从未找到过你的错误,所以我会在这里写下来,供其他发现这篇文章的人参考。

问题在于当你调用:

CreatedAtRoute("GetDocument", new { version = "1", controller = "Document", guid = doc.Guid.ToString("N")}, document);

您正在告诉程序查找一个名为“GetDocument”的函数,该函数接收3个参数,在本例中是3个字符串,但您实际上的“GetDocument”定义只接收1个字符串,即您的“guid”:
[HttpGet("{guid}", Name = "GetDocument")]
public IActionResult GetByGuid(string guid)
{
    var doc = DocumentDataProvider.Find(guid);
    if (doc == null)
        return NotFound();

    return new ObjectResult(doc) {StatusCode = 200};
}

所以为了使其工作,您应该像这样设置:

CreatedAtRoute("GetDocument", new { guid = doc.Guid.ToString("N")}, document);

另一种选择是创建一个带有3个字符串的新get方法,也许你需要将其命名为不同于“GetDocument”的其他名称。

希望这能帮助下一个寻找此解答的人:D


5
我的愚蠢错误在于参数名不一致,比如这里的 guid。调用 createdAtRoute() 时,请确保它们匹配! - Milo
对我有用,没有注意到小}放错了位置。应该被接受为答案,因为它也适用于OP的问题。 - AndreB

20

在我的情况下,是由于复制/粘贴错误导致的。 CreatedAtAction 方法的操作名称参数有误。确保第一个参数(actionName 参数)与操作名称(函数名称)匹配。更正后的代码如下所示:

输入图像描述此处


遇到了同样的问题,但是问题是dotnet scaffolding出现了错误。解决了我的问题。 - JF Gagnon
9
但是actionName参数是用于获取(GET)刚创建的实体的操作。 - Martin Schneider
好棒的发现,救了我的一天 :D - Laurent
在我的情况下,这是因为CreatedAtAction的routeValues参数具有与我所引用的操作所期望的不同的属性名称。因此,Get操作期望一个“customerId”,而routeValues对象具有一个“id”属性。 - Quido
它适用于两种情况。就像图片的名称和获取这些特定资源的操作一样。 - Shihab Uddin

12

4
我刚遇到了相同的问题,但并不是由于程序错误,而是因为我在 CreatedAtRoute("WrongActionMethodName", dto) 中给出了错误的名称。请问需要如何翻译呢? - ataraxia
2
还没有修复。 - TheMisir

5

5

如果你和我一样,不喜欢继承任何内置的ControllerX基类,那么如果你使用以下语句,你可能会遇到这个问题。

  new CreatedAtActionResult(nameof(GetBookOf),
            nameof(BooksController),
            new {id = book.Id.ToString("N")},
            book)

这是因为上述语句的第二个参数期望我们传递构造函数名称,但不包含Controller后缀。

因此,如果按照下面的方式更改,它将正常工作。

  new CreatedAtActionResult(nameof(GetBookOf),
            "Books",
            new {id = book.Id.ToString("N")},
            book)

4
我只是使用了 return CreatedAtAction("ActionMethodName", dto);,直到他们修复那个错误。

4

这个错误出现的另一个原因是当您使用CreatedAtAction返回201时,ASP.NET会在响应中添加一个Location头,其中包含可以访问资源的URL。它使用actionName来实现此目的,因此方法名需要与控制器上的有效方法匹配。例如:

return CreatedAtAction("GetUser", new { id = user.UserId }, user);

如果 GetUser 不存在,调用将失败。更好的做法可能是使用:

return CreatedAtAction(nameof(GetUser), new { id = user.UserId }, user);

开发指南 API文档


4

2
我有相同的症状,但原因是其他问题。基本上,它不喜欢我的操作方法以Async结尾。当我将操作方法从GetAsync重命名为Get,或者在操作中添加[ActionName("GetAsync")]时,它才能正常工作。
来源:https://github.com/microsoft/aspnet-api-versioning/issues/601

2
谷歌搜索引擎让我找到了这个问题,但是方法名称中的“Async”才是实际的问题(aspnet core 3.1)。同时,我还能够修改为[ActionName(nameof(MyMethodAsync))]以对应我的CreateAtAction(nameof(MyMethodAsync), obj, obj) - mdisibio

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接