31

请注意:这个问题是在 2016 年提出的。这个问题的原始答案是更新 microsoft api versiong 包。目前,该问题再次出现,但出于其他原因。

原始问题:


我在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 核心的调试帮助(就像任何现有的路由调试器一样)。

我将不胜感激任何帮助!

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

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

4

13 回答 13

22

ASP.NET 核心 3

为什么会出现这个问题:

“作为解决dotnet/aspnetcore#4849ASP.NET Core MVCtrims the suffix Async from action names by default的一部分。从 ASP.NET Core 3.0 开始,此更改会影响路由和链接生成。”

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

正如@Chris Martinez 在此线程中所说:

改变的原因不是任意的;它解决了一个不同的错误。如果您没有受到上述错误的影响,并且希望像以前一样继续使用 Async 后缀。

怎么解决

重新启用它:

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

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

return CreatedAtAction("PostAsync", dto)

于 2020-09-10T17:14:41.070 回答
18

我知道这篇文章是从 2017 年开始的,但我仍然遇到了同样的问题并最终来到了这里。因为看起来你从来没有发现你的错误,所以我会在这里为创建这篇文章的其他人写下它。

问题是当你打电话时:

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

于 2019-09-27T20:22:38.717 回答
11

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

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

于 2016-09-14T14:43:17.400 回答
8

就我而言,这是一个复制/粘贴错误。该CreatedAtAction方法具有错误的操作名称参数。确保第一个参数(actionName参数)与操作名称(函数名称)匹配。更正后的代码如下所示:

在此处输入图像描述

于 2021-07-29T01:57:13.277 回答
4

我只是使用 returnCreatedAtAction("ActionMethodName", dto);代替,直到他们修复了该错误。

于 2017-10-26T21:01:34.320 回答
3

发生此错误的另一个原因是 b/c 当您使用CreatedAtActionto return201时,ASP.NET 将Location在响应中添加一个标头,其中包含可以访问资源的 url。它使用actionName来执行此操作,因此方法名称需要与控制器上的有效方法匹配。例如:

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

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

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

开发指南 apidocs

于 2020-09-13T02:27:28.147 回答
3

以防万一,如果您像我一样,不喜欢从任何内置的 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)
于 2020-11-28T10:46:48.660 回答
2

我有同样的症状,但原因是别的。基本上它不喜欢我的操作方法以Async. 当我将操作方法​​从GetAsyncto重命名Get或添加[ActionName("GetAsync")]到操作时,它可以工作。

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

于 2020-05-01T04:07:52.793 回答
2

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

我的异步是......

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

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

[ActionName(nameof(GetSCxItemAsync))]
于 2021-05-20T06:52:15.647 回答
1

而不是这个:

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

将您的退货更改为以下内容:

return CreatedAtRoute("GetDocument",doc, null);
于 2019-08-26T18:16:26.713 回答
0

我要在这里为其他一些可怜的不幸的灵魂坚持这个,因为我花了太长时间来弄清楚我做错了什么。

这是错误的:

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

这样做是通过返回默认路由来掩盖问题,即[controller]当您希望它返回时[controller]\{newly generated id}

这是对的:

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

但是,有一个边缘情况会失败,这就是 when user.UserIdis null。我认为这失败了,因为id参数是必需的,所以不能null,因此路由不绑定。它失败是件好事,因为如果它没有失败,那么你将创建一个垃圾路由,但错误消息可能比它可能的更神秘。

在我的情况下,我返回的是输入对象上的 Id,它是 null,而不是输出对象上新生成的 Id。

于 2020-12-30T23:58:50.907 回答
0

您必须为如下方法命名并返回

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

那么您需要在 Post 或 Put 方法中返回 CreatedAtRoute 以通过 Id 等获取项目,例如

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

我必须给出相同的方法名称

于 2022-02-04T16:03:41.013 回答
0

如果您的路线有参数(例如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);

更多内容:用示例解释 ASP.NET Core 中的 Created、CreatedAtAction、CreatedAtRoute 方法

于 2022-02-08T22:18:15.087 回答