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

ASP.NET CORE, Web API: No route matches the supplied values

请注意:这个问题是在 2016 年提出的。这个问题的原始答案是更新 Microsoft api 版本包。最近几天又出现这个问题,不过是其他原因。

原问题:


我在 asp.net 核心(网络 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,将创建文档并创建路由对象,但我收到错误 "No route matches the supplied values" 并获得 500 状态。

我可以直接调用 GetByGuid,没有任何问题。

我找不到 asp.net 核心的任何调试帮助(就像任何现有的路由调试器一样)。

如有任何帮助,我将不胜感激!

编辑 看起来这是来自微软版本控制包的错误。如果我定义修复路径 /api/v1/[Controller] 它正在工作。

但这对我来说不是解决方案。

我会回答我自己的问题: 这确实是微软版本控制包中的一个错误,很快就会被修复。

https://github.com/Microsoft/aspnet-api-versioning/issues/18

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

而不是这个:

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

将您的 return 更改为以下内容:

return CreatedAtRoute("GetDocument",doc, null);

我知道这个 post 是 2017 年的,但我仍然遇到同样的问题并最终来到这里。看起来你从来没有发现你的错误,我会在这里写给其他发现这个错误的人 post。

问题是当你调用:

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

你告诉程序寻找接收 3 个参数的 "GetDocument" 函数,在本例中是 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

我有同样的症状,但原因是别的。基本上它不喜欢我的操作方法以 Async 结尾的事实。当我将操作方法​​从 GetAsync 重命名为 Get 或将 [ActionName("GetAsync")] 添加到操作时,它会起作用。

来源:https://github.com/microsoft/aspnet-api-versioning/issues/601

ASP.net核心3

为什么会出现这个问题:

"As part of addressing dotnet/aspnetcore#4849, ASP.NET Core MVC trims the suffix Async from action names by default. Starting with ASP.NET Core 3.0, this change affects both routing and link generation."

查看更多: https://docs.microsoft.com/en-us/dotnet/core/compatibility/aspnetcore#mvc-async-suffix-trimmed-from-controller-action-names

正如@Chris Martinez 在 this thread 中所说:

The reason for the change was not arbitrary; it addresses a different bug. If you're not affected by said bug and want to continue using the Async suffix as you had been doing.

如何解决

Re-enable它:

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

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

return CreatedAtAction("PostAsync", dto)

出现这个错误的另一个原因是b/c当你使用CreatedAtAction201到return时,ASP.NET会添加一个Location header 到带有可以访问资源的 url 的响应。它使用 actionName 来执行此操作,因此方法名称需要与控制器上的有效方法相匹配。例如:

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

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

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

dev guide apidocs

以防万一,如果你像我一样,不喜欢继承任何内置的 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)

我要为其他一些不幸的人把它贴在这里,因为我花了太长时间才弄明白我做错了什么。

这是错误的:

app.UseEndpoints(endpoints => endpoints.MapDefaultControllerRoute());

这样做是通过 return 默认路由 [controller] 来掩盖问题,而你想要它 return 的是 [controller]\{newly generated id}

这是正确的:

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

然而,在极端情况下会失败,即 user.UserIdnull。我认为这失败了,因为 id 参数是必需的,所以不能是 null,因此路由没有绑定。它失败是件好事,因为如果它没有失败,那么您将创建一条垃圾路由,但错误消息可能比它可能更神秘。

在我的例子中,我 return 输入对象上的 ID 为 null,而不是输出对象上新生成的 ID。

这对我有用... https://www.josephguadagno.net/2020/07/01/no-route-matches-the-supplied-values

我的 get-async 是...

[HttpGet("{id}", Name = nameof(GetSCxItemAsync))]                            
public async Task<ActionResult<SCxItem>> GetSCxItemAsync(Guid id)

但是为了解决路由错误,我不得不在函数声明之前添加以下内容...

[ActionName(nameof(GetSCxItemAsync))]

在我的例子中,这是一个 copy/paste 错误。 CreatedAtAction 方法有错误的操作名称参数。确保第一个参数(actionName 参数)与操作名称(函数名称)匹配。更正后的代码如下所示:

您必须为下面的方法命名,return

    [HttpGet("{id}",Name = "MethodName")]
    public async Task<IActionResult> MethodName(int id)
    {
        var baseItem = await _baseItemService.BaseItemByIdAsync(baseItemId);
        return Ok(baseItem);
    }

然后你需要 return Post 中的 CreatedAtRoute 或 Put 方法来通过 Id 等获取项目,例如

var (errorMessage, baseItem) = await _baseItemService.AddBaseItem(model);
if (baseItem != null) return CreatedAtRoute("MethodName", new { baseItemId = baseItem.BaseItemId }, baseItem);
return BadRequest(errorMessage );

我必须给出相同的方法名

如果你的路线有参数(例如GetbookById(int id))那么你需要3个部分到CreatedAtRoute例如:

book b = new book(); // The Created new book.
var routeValues = new { id = book.Id}; // Represents the parameter(s) to GetbookById
return CreatedAtRoute( nameof(GetbookById), routeValues, b);

更多内容:Created, CreatedAtAction, CreatedAtRoute Methods In ASP.NET Core Explained With Examples