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

18

52

PLEASE NOTE: This question was asked in 2016. The original answer to this problem was to update the microsoft api versiong package. In the current days, the problem reoccurs, but for other reasons.

Original Question:


i have some problems with the routing in asp.net core (web api).

I have this Controller (simplified):

[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;
}
}

If i call Create, the document is created and the routing object was created but i get the error "No route matches the supplied values" and get a 500 status.

I can call the GetByGuid directly, without any problems.

I couldn't find any debugging help for asp.net core (like any existing routing debugger).

I would appreciate any help!

EDIT Looks like it would be a bug from microsoft's versioning package.. if i define the fix route /api/v1/[Controller] it's working.

But that's not a solution for me.

Hunchback answered 12/9, 2016 at 21:52 Comment(0)
H
12

I'll answer my own question: It was really a bug in the versioning package of microsoft and it's gonna be fixed soon.

ASP.Net Core: internal routing fails with CreatedAtRoute #18

Hunchback answered 14/9, 2016 at 14:43 Comment(2)
I've just had the same issue though it's not due to the bug, I had given the wrong name in the CreatedAtRoute("WrongActionMethodName", dto).Stagecraft
And have not fixed yetSummitry
W
57

ASP.net core 3

Why this problem occurs:

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.

See more:
ASP.NET Core 3.0-3.1 | Breaking Changes | Async suffix trimmed from controller action names

As @Chris Martinez says in this Github Issue:
.Net Core 3.0 and using CreatedAtRoute result in No route matches the supplied values. #558:

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.

How to solve

Re-enable it:

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

You should now pass the createActionName parameter including the Async suffix like this:

return CreatedAtAction("PostAsync", dto)

Webster answered 10/9, 2020 at 17:14 Comment(3)
I tested it on dot net 5.0. It works, thank you.Flybynight
Thank you very much, worked on .net6 with a small change; services.AddControllersWithViews(options => { options.SuppressAsyncSuffixInActionNames = false; });Brush
Thanks, I rename my action name from GetByIdAsync() to GetById().Idell
M
33

I know this post is from 2017 but still i just faced the same problem and ended up here. And as it looks like you never found your mistake I'll write it here for anyone else that founds this post.

The problem is that when you call:

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

You are telling the program to look for a "GetDocument" function that receives 3 parameters, in this case 3 strings but your actual "GetDocument" definition receives only 1 string that is your "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};
}

So for it to work you should have it like this:

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

Another option would be to create a new get method with 3 strings and maybe you'll have to call it something different than "GetDocument".

Hope this helps the next one that comes looking for this :D

Mientao answered 27/9, 2019 at 20:22 Comment(2)
My silly mistake was not being consistent with the parameter names i.e. guid here. Make sure they match when calling the createdAtRoute()!Thyme
Worked for me, did not notice the little } at the wrong place. Should be the accepted answer as it also works for the OP's questionMochun
W
21

In my case it was a copy/paste error. The CreatedAtAction method had the wrong action name parameter. Make sure the first parameter (the actionName parameter) matches the action name (the function name). The corrected code is seen below:

enter image description here

Washwoman answered 29/7, 2021 at 1:57 Comment(5)
Had the same issue but it's dotnet scaffolding which is wrong. Save my day.Housman
But the actionName parameter is intended for the action where you can retrieve (GET) the just created entity.Endomorphic
Nice catch, save my day :DOscillogram
In my case it was because the routeValues parameter to CreatedAtAction had different property names than the action that I was referring to expected. So the Get expected a "customerId" and the routeValues object had an "id" property.Sentimentalize
it works for both cases. Like the same name as the picture & the action to get these Specific resources.Shortly
H
12

I'll answer my own question: It was really a bug in the versioning package of microsoft and it's gonna be fixed soon.

ASP.Net Core: internal routing fails with CreatedAtRoute #18

Hunchback answered 14/9, 2016 at 14:43 Comment(2)
I've just had the same issue though it's not due to the bug, I had given the wrong name in the CreatedAtRoute("WrongActionMethodName", dto).Stagecraft
And have not fixed yetSummitry
E
6

This worked for me... https://www.josephguadagno.net/2020/07/01/no-route-matches-the-supplied-values

my get-async was...

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

but in order to get around route error I had to add the following before the function declaration...

[ActionName(nameof(GetSCxItemAsync))]
Examinee answered 20/5, 2021 at 6:52 Comment(0)
M
5

Just in case, if you are like me, don't like to inherit from any of the in built ControllerX base classes, then you might face this issue, if you use following statement

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

It's because second parameter in the above statement, expect us to pass the constructor name without Controller suffix.

Hence, if you change like following, then it would work just fine.

  new CreatedAtActionResult(nameof(GetBookOf),
            "Books",
            new {id = book.Id.ToString("N")},
            book)
Middelburg answered 28/11, 2020 at 10:46 Comment(0)
T
4

I just used return CreatedAtAction("ActionMethodName", dto); instead until they fix that bug.

Trucker answered 26/10, 2017 at 21:1 Comment(0)
J
4

I had the same symptoms but the cause was something else. Basically it doesn't like the fact that my action method ends with Async. It works when I either rename the action method from GetAsync to Get, or add [ActionName("GetAsync")] to the action.

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

Jehol answered 1/5, 2020 at 4:7 Comment(1)
Google search led me to the question but this issue with Async in the method name was the actual problem (aspnet core 3.1). Also, was able to modify as [ActionName(nameof(MyMethodAsync))] to correspond with my CreateAtAction(nameof(MyMethodAsync), obj, obj)Snowman
S
4

Another reason this error occurs is b/c when you use the CreatedAtAction to return 201, ASP.NET will add a Location header to the response with the url where the resource can be accessed. It uses the actionName to do this, so the method name needs to match a valid method on your controller. For example:

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

If GetUser does not exist, the call will fail. Better practice probably to use:

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

dev guide apidocs

Squeak answered 13/9, 2020 at 2:27 Comment(0)
W
4

If your route has parameters (for example GetbookById(int id)) then you need 3 parts to the CreatedAtRoute for example:

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);

More in: Created, CreatedAtAction, CreatedAtRoute Methods In ASP.NET Core Explained With Examples

Wetzel answered 8/2, 2022 at 22:18 Comment(0)
S
2

I'm going to stick this in here for some other poor unfortunate soul as I've spent far too long working out what I was doing wrong.

This is wrong:

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

What this does is mask the problem by returning the default route which is [controller], when what you want it to return is [controller]\{newly generated id}.

This is correct:

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

However there is an edge case where this fails, this being when user.UserId is null. I think that this fails because the id parameter is required, so cannot be null, thus the route doesn't bind. It's good that it fails because if it didn't then you would be creating a junk route, but the error message is more cryptic than perhaps it could be.

In my case I was returning the Id on the input object, which was null, not the newly generated Id on the output object.

Shaunteshave answered 30/12, 2020 at 23:58 Comment(0)
S
2

This syntax solves the problem for me:

[HttpGet("{id:int}", Name = "GetVilla")]
public ActionResult<Villa> Get(int id)
{
    // Your logic here
    return StatusCode(StatusCodes.Status200OK, villa);
}

[HttpPost("CreateVilla")]
public IActionResult Create([FromBody]Villa villa)
{
    // Your logic here
    return CreatedAtRoute("GetVilla", new { id = villa.Id }, villa);
}

Edit: When you declare the 'GetVilla' endpoint, you're essentially defining a route named 'GetVilla' with the HTTP verb 'HttpGet' and an 'id' parameter. The 'HttpGet' attribute specifies that this endpoint will handle HTTP GET requests, and the 'id:int' indicates that the 'id' parameter must be an integer.

In the Create method, the 'CreatedAtRoute' method is utilized to generate a response with a 201 Created status code. The parameters passed to 'CreatedAtRoute' specify the route name (GetVilla) and its corresponding parameters (id = villa.Id). This constructs a URL pointing to the newly created resource. Finally, the method returns the created resource itself.

This setup ensures that when a resource is created, clients receive a clear reference to it through the Location header, facilitating proper RESTful behavior and seamless resource access.

Also make sure there is no spaces in "{id:int}".

Spelling answered 10/2 at 14:29 Comment(0)
F
1

Instead of this:

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

Change your return to the following:

return CreatedAtRoute("GetDocument",doc, null);
Fragrant answered 26/8, 2019 at 18:16 Comment(0)
O
0

you must give a name for a method like below and return

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

then you need return CreatedAtRoute in Post or Put Method to get Item by Id or etc such as

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

me must give the same method name

Outer answered 4/2, 2022 at 16:3 Comment(0)
S
0

I had similar issues though not with get-async. It turned out that I was using a wrong action name, the easiest work around is to ensue your using the correct action name and I advice sometimes to just copy and past it.

Sanitarian answered 15/10, 2022 at 20:21 Comment(0)
C
0

This error occurs due to the confusion between the method overloads for CreatedAtAction method

overload methods for CreatedAtAction

It is suffice if you could give prefix the parameter names before you pass them as input to the CreatedAtAction method as below

 return CreatedAtAction(actionName: "GetDocument", routeValues: new { id = yourDTO.Id }, value: yourDTOObject);

This helped me!

Concave answered 17/4, 2023 at 13:50 Comment(0)
J
0

After Setting the options.SuppressAsyncSuffixInActionNames = false; in Program.cs file don't forgot to pass the third parameter in CreatedAtAction

CreatedAtAction(nameof(GetProductByIdAsync), new { id = newProduct.Id }, newProduct);
Jeremyjerez answered 16/1 at 14:2 Comment(0)
S
-1

I faced the same issue recently. And it seems it has nothing to do with CreatedAtRoute(). I got the same error with CreatedAtAction()

I got it resolved by adding this code in my Program.cs file.

builder.Services.AddMvc(options => options.SuppressAsyncSuffixInActionNames = false);

I was trying to access the action method named GetWalkAsync(Guid id). As this method has 'Async' at the end, Dot net was removing 'Async' or suppressing this from the end of the Action method. As a result it became GetWalks(Guid id) which is not a valid route. Hence I was getting this error.

You can check out this repo's Program.cs file and WalksController.cs file's CreatedWalk() action method, for reference.

Spinnaker answered 21/6 at 12:24 Comment(1)
This has nothing to do with the initial question though, as that makes no mention of async whatsoeverMortmain

© 2022 - 2024 — McMap. All rights reserved.