Can anyone explain CreatedAtRoute() to me?

When you use CreatedAtRoute, the first argument is the route name of the GET to the resource. The trick that is not so obvious is that, even with the correct method name specified, you must thus use the Name param on the HttpGet attribute for it to work.

So if the return in your POST is this:

return CreatedAtRoute("Get", routeValues: new { id = model.Id }, value: model);

Then your Get method attribute should look like this even if your method is named Get:

[HttpGet("{id}", Name = "Get")]

Calls to your Post method will not only return the new object (normally as JSON), it will set the Location header on the response to the URI that would get that resource.

NOTE the field names in the routeValues field names need to match the binding names in the target route, i.e. there needs to be a field named id to match the {id} in HttpGet("{id}"

Finally, in some cases, it should be mentioned that the CreatedAtAction helper can be a more direct solution.


In .net core WebAPI, you use this method to return a 201 code, which means that the object was created.

[Microsoft.AspNetCore.Mvc.NonAction]
public virtual Microsoft.AspNetCore.Mvc.CreatedAtRouteResult CreatedAtRoute (string routeName, object routeValues, object content);

As you can see above, the CreatedAtRoute can receive 3 parameters:

routeName Is the name that you must put on the method that will be the URI that would get that resource after created.

routeValues It's the object containing the values that will be passed to the GET method at the named route. It will be used to return the created object

content It's the object that was created.

The above example shows the implementation of two methods of a simple controller with a simple GET method with the bonded name and the POST method that creates a new object.

[Route("api/[controller]")]
[ApiController]
public class CompanyController : Controller
{
    private ICompanyRepository _companyRepository;

    public CompanyController(ICompanyRepository companyRepository)
    {
        _companyRepository = companyRepository;
    }

    [HttpGet("{id}", Name="GetCompany")]
    public IActionResult GetById(int id)
    {
        Company company = _companyRepository.Find(id);

        if (company == null)
        {
            return NotFound();
        }
        
        return new ObjectResult(company);
    }

    [HttpPost]
    public IActionResult Create([FromBody] Company company)
    {
        if (company == null)
        {
            return BadRequest();
        }

        _companyRepository.Add(company);

        return CreatedAtRoute(
            "GetCompany",
            new { id = company.CompanyID },
            company);
    }
}

IMPORTANT

  1. Notice that the first parameter at CreatedAtRoute (routeName), must be the same at the definition of the Name at the Get method.

  2. The object on the second parameter will need to have the necessary fields that you use to retrieve the resource on the Get method, you can say that it's a subset of the object created itself

  3. The last parameter is the company object received in the body request in it's full form.

FINALY

As final result, when the Post to create a new company got made to this API, you will you return a route like 'api/company/{id}' that will return to you the newly created resource


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

BTW I agree that the MSDN article is of no use in understanding this. The route you actually return will naturally depend on your routing setup.