【问题标题】:ASP.net Core RC2 Web API POST - When to use Create, CreatedAtAction, vs. CreatedAtRoute?ASP.net Core RC2 Web API POST - 何时使用 Create、CreatedAtAction 和 CreatedAtRoute?
【发布时间】:2016-10-16 19:05:26
【问题描述】:

这些功能的根本区别是什么?我只知道这三个结果都是 201,这适用于成功的 POST 请求。

我只关注我在网上看到的示例,但他们并没有真正解释他们为什么要做他们正在做的事情。

我们应该为我们的 GET 提供一个名称(1 条记录按 id):

[HttpGet("{id}", Name="MyStuff")]
public async Task<IActionResult> GetAsync(int id)
{
     return new ObjectResult(new MyStuff(id));
}

命名这个get函数的目的是什么,除了它“可能”是下面的POST函数所必需的:

[HttpPost]
public async Task<IActionResult> PostAsync([FromBody]MyStuff myStuff)
{
     // actual insertion code left out

     return CreatedAtRoute("MyStuff", new { id = myStuff.Id }, myStuff);
}

我注意到CreatedAtRoute 也有一个不包含路由名称的重载。

还有CreatedAtAction 接受类似的参数。为什么会存在这种变体?

还有Created 需要一个URL 和我们想要返回的对象。我可以只使用这个变体并提供一个虚假的 URL 并返回我想要的对象并完成它吗?

我不确定为什么有这么多变体只是为了能够向客户端返回 201。在大多数情况下,我想要做的就是返回“应用程序分配”(很可能来自数据库)唯一 id 或我的实体的具有最少信息的版本。

我认为最终,一个 201 响应“应该”创建一个包含新创建资源的 URL 的位置标头,我相信所有 3 个及其重载最终都会这样做。为什么我应该总是返回一个位置标头?我的 JavaScript 客户端、原生移动和桌面应用程序从不使用它。例如,如果我发出 HTTP POST 来创建账单并将其发送给用户,那么这样的位置 URL 会是什么? (我很抱歉没有深入挖掘互联网的历史来寻找答案。)

为什么要为动作和路由命名?动作名和路由名有什么区别?

我对此感到困惑,所以我求助于返回 Ok(),它返回 200,这不适合 POST。

【问题讨论】:

    标签: asp.net-web-api http-post asp.net-core asp.net-core-mvc


    【解决方案1】:

    这里有几个不同的问题可能应该分开,但我认为这涵盖了您的大部分问题。

    为什么要为动作和路由命名?动作名和路由名有什么区别?

    首先,动作和路线是非常不同的。

    动作存在于控制器上。路由指定了一个完整的端点,该端点由控制器、操作和可能的其他其他路由参数组成。

    您可以为路由命名,这样您就可以在应用程序中引用它。例如

    routes.MapRoute(
      name: "MyRouteName",
      url: "SomePrefix/{action}/{id}",
      defaults: new { controller = "Section", action = "Index" }
    );
    

    动作名称的原因包含在这个问题中:Purpose of ActionName

    它允许您以数字开始您的操作或在标识符中包含 .net 不允许的任何字符。 - 最常见的原因是它允许您有两个具有相同签名的操作(请参阅任何脚手架控制器的 GET/POST 删除操作)

    这些功能的根本区别是什么?

    这 3 个函数基本上都执行相同的功能 - 返回一个 201 Created 响应,带有一个指向新创建响应的 url 的 Location 标头,以及主体中的对象本身。 url 应该是 GET 请求返回对象 url 的 url。这将被视为 RESTful 系统中的“正确”行为。

    对于您问题中的示例邮政编码,您实际上希望使用CreatedAtAction

    [HttpPost]
    public async Task<IActionResult> PostAsync([FromBody]MyStuff myStuff)
    {  
       // actual insertion code left out
    
       return CreatedAtAction("MyStuff", new { id = myStuff.Id }, myStuff);
    }
    

    假设您配置了默认路由,这将添加一个 Location 标头,指向同一控制器上的 MyStuff 操作。

    如果您希望位置 url 指向特定路线(如我们之前定义的,您可以使用例如

    [HttpPost]
    public async Task<IActionResult> PostAsync([FromBody]MyStuff myStuff)
    {  
       // actual insertion code left out
    
       return CreatedAtRoute("MyRouteName", new { id = myStuff.Id }, myStuff);
    }
    

    我可以只使用这个变体并提供一个虚假的 URL 并返回我想要的对象并完成它吗?

    如果你真的不想使用CreatedResult,你可以使用一个简单的StatusCodeResult,它会返回一个201,没有Location Header 或body。

    [HttpPost]
    public async Task<IActionResult> PostAsync([FromBody]MyStuff myStuff)
    {  
      // actual insertion code left out
    
      return StatusCode(201);
    }
    

    【讨论】:

    • 我不确定 .NET Core,但 Content&lt;T&gt;(HttpStatusCode, T content) 方法是否仍然存在以返回状态代码和内容?这应该允许返回 201 以及新创建的对象,而不包括 Location 标头。
    • 该重载似乎不再存在,但实际上有一个 StatusCode 重载,您可以类似地使用:StatusCode(int httpStatusCode, object value)
    • 似乎[HttpGet("{id}", Name = "GetUser",Order = 0)] 创建路由的方式似乎不适用于 CreatedAtRoute()
    • 带有一个 Location 标头,指向新创建的响应的 URL,以及主体中的对象本身。我很抱歉,但我无法理解这一点。请你解释清楚好吗?
    【解决方案2】:

    最新文档https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/routing?view=aspnetcore-3.1 中提到,这一切都非常令人困惑

    看起来“他们”不希望在即将到来的时代发展成为一个简单的过程......

    【讨论】:

      猜你喜欢
      • 2020-12-23
      • 2016-11-14
      • 2017-10-06
      • 2016-10-14
      • 1970-01-01
      • 2016-08-02
      • 2020-12-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多