Inside my ASP.NET Core app I have a controller action like this:
[HttpPost] public async Task<IActionResult> CreateSubscriber([FromBody] SubscriberDef subscriber) { //...implementation removed var link = Url.Link("SubscriberLink", new { id = subscriber.ID }); return Created(link, null); }
The above code works as expected. However, if I use the built-in method "CreatedAtRoute", then I get an exception:
[HttpPost] public async Task<IActionResult> CreateSubscriber([FromBody] SubscriberDef subscriber) { //...implementation removed return CreatedAtRoute("SubscriberLink", new { id = subscriber.ID }); }
The exception is:
System.InvalidOperationException: No route matches the supplied values.
The exception causes the service to return a 500 status code.
It is the same route in either case, so I don't know why the first example works correctly and the second does not.
My project.json
contains this:
"frameworks": { "dnx46": { }, "dnxcore50": { } },
For reference sake, the named route is composed from two pieces. First is the controller prefix:
[Route("api/[controller]")] public class SubscribersController : Controller { // ... }
Second is the GET action, where the actual "SubscriberLink"
route is named:
[HttpGet("{id}", Name = "SubscriberLink")] [SwaggerResponse(HttpStatusCode.OK, Type = typeof(Subscriber))] public async Task<IActionResult> GetSubscriber(Guid id) { //...implementation removed... return Ok(subscriber); }
Thoughts?
CreatedAtRoute (object routeValues, object value) By default, if no information about target route is passed, it will take the path of the current method and use it for creating Location header. In the following example it takes the route of POST method and attaches all route values as query parameters.
The CreatedAtRoute method is intended to return a URI to the newly created resource when you invoke a POST method to store some new object. So if you POST an order item for instance, you might return a route like 'api/order/11' (11 being the id of the order obviously).
You are using the wrong overload of CreatedAtRoute
. Use the overload that takes three arguments instead.
For instance, the following works on my machine.
[Route("api/[controller]")] public class SubscribersController : Controller { public IActionResult Index() { var subscriber = new { Id = Guid.NewGuid(), FirstName = "Shaun", LastName = "Luttin" }; // overload with three arguments return CreatedAtRoute( routeName: "SubscriberLink", routeValues: new { id = subscriber.Id }, value: subscriber); } [HttpGet("{id}", Name = "SubscriberLink")] public IActionResult GetSubscriber(Guid id) { var subscriber = new { Id = id, FirstName = "Shaun", LastName = "Luttin" }; return new JsonResult(subscriber); } }
The result is a 201 response. The response's body contains details of the entity we created (the value
argument) and the response's Location header contains a URI to the entity.
There are three overloads for CreatedAtRoute
.
CreatedAtRoute(object routeValues, object value) CreatedAtRoute(string routeName, object value) CreatedAtRoute(string routeName, object routeValues, object value)
If we want to pass a route name and route values, we use the overload that takes three arguments. If we do not want to return details of the entity we created, we can pass null
for the third argument,
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With