有人能解释一下CreatedAtRoute()吗?

179

对于Web API 2的模板,post方法通常如下所示:

[ResponseType(typeof(MyDTO))]
public IHttpActionResult PostmyObject(MyDTO myObject)
{
    ...
    return CreatedAtRoute("DefaultApi", new { id = myObject.Id }, myObject);
}

我不理解这个 CreatedAtRoute() 方法。有人能解释一下吗?


39
当然,我找到了那些谷歌搜索结果。我的问题是这些文件没有帮助我理解这种方法,我读完它们后仍然不明白。这就是为什么我在这里提问的原因。 - martial
20
如果我可以通过谷歌找到答案,为什么要花时间编辑问题并在这里提问呢? - martial
11
谢谢您提出这个问题 :) - Vidar
3个回答

186
CreatedAtRoute 方法旨在在调用 POST 方法存储新对象时返回指向新创建资源的 URI。例如,如果您提交了一个订单项,则可能会返回如 'api/order/11' 的路由(其中 11 显然是订单的 ID)。
顺便说一下,我同意 MSDN 文章对理解此内容没有帮助。实际返回的路由将自然取决于您的路由设置。

15
它实际返回的是一个CreatedAtRouteNegotiatedContentResult<myObject>对象!如果在你的操作上运行单元测试,你将看到这个。然而,在HTTP上下文中运行时,它将在响应体中返回序列化对象,但你应该在响应头中看到指向资源的链接。顺便说一句,如果你认为我回答了问题,请标记为答案。 - see sharper
3
谢谢,这回答了我的问题。 - martial
2
您提供的路由将出现在响应中的位置标头中。这是相当典型的REST行为。 - Jeff Martin
5
当 MyObject 没有返回,但是我为什么需要将它传递给 CreatedAtRoute?这个方法会对它做什么? - Elisabeth
7
有没有一种方法可以使用当前路由? 例如,如果我在文件控制器中使用[Route("[controller]")]创建一个对象,在返回什么(以便可以使用URL调用相邻的GET操作)? - Shimmy Weitzhandler
显示剩余9条评论

36
当您使用CreatedAtRoute时,第一个参数是指向资源的GET路由名称。并非显而易见的技巧是,即使指定了正确的方法名称,您也必须在HttpGet属性上使用Name参数才能使其正常工作。
因此,如果您的POST返回如下内容:
return CreatedAtRoute("Get", routeValues: new { id = model.Id }, value: model);

即使您的方法名为Get,您的Get方法属性也应该像这样:

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

调用您的Post方法不仅会返回新对象(通常为JSON格式),而且还会在响应的Location头中设置可以获取该资源的URI。

请注意,routeValues字段中的字段名称需要与目标路由中的绑定名称匹配,即需要有一个名为id的字段来匹配{id}HttpGet("{id}"中的。

最后,有些情况下,应该提到CreatedAtAction助手可能是更直接的解决方案。


“这不仅会返回新对象(通常为JSON),还会在响应中设置Location头,指向获取该资源的URI。” “这”是指HttpGet还是HttpPost?另外,“它将在响应中设置Location头,指向获取该资源的URI。”是什么意思? - Tran Anh Minh
"This" 是指 HttpPost 方法(请编辑答案)。至于您关于 Location header 的问题,它是一个 Http Header,客户端可以决定执行某些操作,例如自动重定向到该位置。这是一个标准的 Http 响应头(https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Standard_response_fields)。 - Scott Blasingame
非常感谢您发布这篇文章...我刚刚花了整整两个小时试图摆脱"No route matches the supplied values",尝试了我能想到的所有值的可能组合,只是发现我必须确保new-up并将用户名分配给user.UserName,我认为这不会成为问题,因为我已经有了字符串值可用于UserName,结果证明一直都是这个原因...真是令人沮丧。我的返回值如下:return CreatedAtRoute("GetUser", routeValues: new {username = user.UserName}, _mapper.Map<PhotoDto>(photo)); - Andrey Vasilyev

20
在 .net core WebAPI 中,您可以使用此方法返回 201 状态码,表示对象已创建。
[Microsoft.AspNetCore.Mvc.NonAction]
public virtual Microsoft.AspNetCore.Mvc.CreatedAtRouteResult CreatedAtRoute (string routeName, object routeValues, object content);

如上所示,CreatedAtRoute 方法可以接收 3 个参数:

routeName 是您必须在方法中输入的名称,该方法将是在创建后获取该资源的 URI。

routeValues 是包含将传递给命名路由的 GET 方法的值的对象。它将用于返回创建的对象。

content 是已创建的对象。

上面的示例展示了一个简单控制器的两种方法的实现,其中包括具有绑定名称的简单 GET 方法和创建新对象的 POST 方法。

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

重要提示

  1. 请注意,在CreatedAtRoute(routeName)的第一个参数必须与Get方法中Name的定义相同。

  2. 第二个参数中的对象将需要具有用于在Get方法中检索资源所使用的必要字段,可以说它是创建的对象本身的子集。

  3. 最后一个参数是在请求主体中接收到的完整公司对象。

最终结果

作为最终结果,当向此API提交创建新公司的Post时,您将返回类似于“api/company/{id}”的路由,该路由将返回新创建的资源。


3
这个回答被低估了。我确实理解了这里的意思。 - Navjot Singh
这个答案帮助我理解了“什么”,但为什么或如何使用它呢? - PixelPaul

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接