我在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);
var val = CreatedAtRoute("GetDocument", new { version = "1", controller = "Document", guid = doc.Guid.ToString("N")}, document);
return val;
}
}
如果我调用Create,则会创建文档并创建路由对象,但是我收到错误"没有路由匹配提供的值"并获得500状态。
我可以直接调用GetByGuid,没有任何问题。
我无法找到asp.net核心的任何调试帮助(就像任何现有的路由调试器一样)。
我将不胜感激任何帮助!
修改 看起来这将是微软的版本控制包中的一个错误..如果我定义修复路由/ api / v1 / [控制器]它正在工作。
但那对我来说不是解决方案。
答案 0 :(得分:6)
我会回答我自己的问题: 这真是微软版本化软件包中的一个错误,它很快就会修复。
https://github.com/Microsoft/aspnet-api-versioning/issues/18
答案 1 :(得分:3)
“作为寻址dotnet/aspnetcore#4849的一部分, ASP.NET Core MVC
trims the suffix Async from action names by default
。从ASP.NET Core 3.0开始,此更改会影响路由和链接的生成。”
@Chris Martinez在this thread中说:
更改的原因并非任意;它解决了另一个错误。如果您不受上述错误的影响,并希望像往常一样继续使用Async后缀。
重新启用它:
services.AddMvc(options =>
{
options.SuppressAsyncSuffixInActionNames = false;
});
您现在应该像这样传递包含后缀createActionName
的{{1}}参数:
Async
答案 2 :(得分:2)
我只是使用了返回CreatedAtAction("ActionMethodName", dto);
,直到他们修复了该错误。
答案 3 :(得分:2)
我知道这篇文章来自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的人。
答案 4 :(得分:2)
我有相同的症状,但原因是其他原因。基本上,我的操作方法以Async
结尾的事实并不令人满意。当我将操作方法从GetAsync
重命名为Get
或将[ActionName("GetAsync")]
添加到操作中时,它就起作用了。
来源:https://github.com/microsoft/aspnet-api-versioning/issues/601
答案 5 :(得分:1)
当您使用CreatedAtAction
返回201
时,发生此错误的另一个原因是b / c,ASP.NET会向响应中添加一个Location
标头,并在URL中添加资源可以访问。它使用actionName
来执行此操作,因此方法名称需要与控制器上的有效方法匹配。例如:
return CreatedAtAction("GetUser", new { id = user.UserId }, user);
如果GetUser
不存在,则呼叫将失败。可能使用更好的做法:
return CreatedAtAction(nameof(GetUser), new { id = user.UserId }, user);
答案 6 :(得分:1)
这对我有用... 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))]
答案 7 :(得分:0)
代替此:
<span>
<a [href]="getFileLink(document.docID)" target="_blank">
{{document.comments}}
</a>
</span>
将您的退货更改为以下内容:
CreatedAtRoute("GetDocument", new { version = "1", controller = "Document", guid = doc.Guid.ToString("N")}, document);
答案 8 :(得分:0)
大多数其他答案提到的答案,我已经尝试过了,但是没有用。但是我知道,如果我们在您的启动课程中将endpoints.MapControllers();
更改为endpoints.MapDefaultControllerRoute();
,该错误将消失:
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute(); // MapControllers();
});
,如果您想查看这两个端点的不同之处,可以visit this。
答案 9 :(得分:0)
以防万一,如果您像我一样,不喜欢从任何内置的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)
答案 10 :(得分:0)
我要为其他一些不幸的灵魂坚持这一点,因为我花了太长时间弄清楚我做错了什么。
这是错误的:
app.UseEndpoints(endpoints => endpoints.MapDefaultControllerRoute());
这样做是通过返回默认路由 [controller]
来掩盖问题,而您希望它返回的是 [controller]\{newly generated id}
。
这是正确的:
return CreatedAtAction(nameof(GetUser), new { id = user.UserId }, user);
然而,有一种边缘情况会失败,即 user.UserId
为 null
。我认为这失败是因为需要 id
参数,所以不能是 null
,因此路由没有绑定。它失败是件好事,因为如果没有,那么您将创建一个垃圾路由,但错误消息可能比它可能更神秘。
在我的例子中,我返回的是输入对象上的 Id,它是空的,而不是输出对象上新生成的 Id。
答案 11 :(得分:0)