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."
正如@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当你使用CreatedAtAction
到201
到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);
以防万一,如果你像我一样,不喜欢继承任何内置的 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.UserId
为 null
。我认为这失败了,因为 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
请注意:这个问题是在 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."
正如@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当你使用CreatedAtAction
到201
到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);
以防万一,如果你像我一样,不喜欢继承任何内置的 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.UserId
为 null
。我认为这失败了,因为 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