【问题标题】:How can I code a Created-201 response using IHttpActionResult如何使用 IHttpActionResult 编写 Created-201 响应
【发布时间】:2014-07-16 12:55:47
【问题描述】:

如何使用 IHttpActionResult 编写 Created-201 响应?

IHttpActionResult只有这些选项

  • 好的
  • 列表项
  • 未找到
  • 异常
  • 未经授权
  • 错误请求
  • 冲突重定向
  • InvalidModelState

我现在正在做的是下面的这段代码,但我想使用IHttpActionResult 而不是HttpResponseMessage

public IHttpActionResult Post(TaskBase model)
{
    HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, model);
    response.Headers.Add("Id", model.Id.ToString());
    return ResponseMessage(response);
}

【问题讨论】:

  • 这里有一个实现strathweb.com/2013/06/… 但我真的不喜欢这个。我更喜欢使用HttpResponseMessage,我可以指定所有动词和主体,只需调用Request.CreateRespose() 方法。

标签: c# asp.net asp.net-web-api response asp.net-web-api2


【解决方案1】:

如果您的视图派生自ApiController,您应该能够从基类调用Created 方法来创建这样的响应。

示例:

[Route("")]
public async Task<IHttpActionResult> PostView(Guid taskId, [FromBody]View view)
{
    // ... Code here to save the view

    return Created(new Uri(Url.Link(ViewRouteName, new { taskId = taskId, id = view.Id })), view);
}

【讨论】:

  • 如何使用我当前的 API 控制器添加 Uri?
  • @Devsined 你的控制器是否继承自ApiController
  • 是的。我可以选择返回 Created。但是我很难返回控制器的 Uri 和 id。我现在返回任何 Uri。
  • 或者,更好的是 CreatedAtRoute msdn.microsoft.com/en-us/library/…
【解决方案2】:

在 ASP.NET Core 中,可以返回 IActionResult。这意味着您可以返回带有 201 状态代码的 ObjectResult

[HttpPost]
public async Task<IActionResult> PostAsync([FromBody] CreateModel createModel)
{
    // Create domain entity and persist
    var entity = await _service.Create(createModel);

    // Return 201
    return new ObjectResult(entity) { StatusCode = StatusCodes.Status201Created };
}

【讨论】:

  • 自 2016 年以来,您是否遇到过 swagger,为什么这不适合它?
  • 我认为使用 swagger 您可以在方法上方添加属性,告诉 swagger 可能的返回状态以及对象形状是什么
  • 也许“应该”在这里不是正确的词。它可能”。您可以返回实际模型或抛出异常,这在许多情况下更优雅。
【解决方案3】:
return Content(HttpStatusCode.Created, "Message");

内容正在返回 NegotiatedContentResult。 NegotiatedContentResult 是实现 IHttpActionResult。

类似的问题:如果你想随消息一起发送 NotFound。

return Content(HttpStatusCode.NotFound, "Message");

或者:

return Content(HttpStatusCode.Created, Class object);
return Content(HttpStatusCode.NotFound, Class object);

【讨论】:

    【解决方案4】:

    我知道这是一个旧线程,但您可能想看看我的解决方案 here。它比需要的多一点,但肯定会完成这项工作。

    步骤:

    定义一个自定义属性:

    [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
    public sealed class UniqueIdAttribute: Attribute
        {
        }
    

    使用自定义属性装饰模型的唯一标识属性:

       public class Model
        {
            public List<Model> ChildModels { get; set; }
            [UniqueId]
            public Guid ModelId { set; get; }
            public Guid ? ParentId { set; get; }
            public List<SomeOtherObject> OtherObjects { set; get; }
        }
    

    向继承自 ApiController 的 BaseController 添加一个新的 Created(T yourobject); 方法。从此 BaseController 继承所有控制器:

    CreatedNegotiatedContentResult<T> Created<T>(T content)
        {
            var props =typeof(T).GetProperties()
            .Where(prop => Attribute.IsDefined(prop, typeof(UniqueIdAttribute)));
            if (props.Count() == 0)
            {
                //log this, the UniqueId attribute is not defined for this model
                return base.Created(Request.RequestUri.ToString(), content);
            }
            var id = props.FirstOrDefault().GetValue(content).ToString();
            return base.Created(new Uri(Request.RequestUri + id), content);
         }
    

    它非常简单,无需担心每种方法都写这么多。您只需拨打Created(yourobject);

    如果您忘记装饰或无法装饰您的模型(出于某种原因),Created() 方法仍然有效。但是,位置标头会丢失 Id。

    您对该控制器的单元测试应该解决这个问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-11-24
      • 1970-01-01
      • 2015-04-19
      • 2021-01-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多