25

How can I code a Created-201 response using IHttpActionResult ?

IHttpActionResult has only these options

  • Ok
  • List item
  • NotFound
  • Exception
  • Unauthorized
  • BadRequest
  • Conflict Redirect
  • InvalidModelState

What I am doing now is this code below, but I would like to use IHttpActionResult and not HttpResponseMessage

public IHttpActionResult Post(TaskBase model)
{
    HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, model);
    response.Headers.Add("Id", model.Id.ToString());
    return ResponseMessage(response);
}
Mauro Bilotti
  • 5,628
  • 4
  • 44
  • 65
Devsined
  • 3,363
  • 6
  • 30
  • 48
  • 1
    There is a implementation here http://www.strathweb.com/2013/06/ihttpactionresult-new-way-of-creating-responses-in-asp-net-web-api-2/ but I really doesn't like this. I prefer work with `HttpResponseMessage` which I can speficy all verbs and body just called `Request.CreateRespose()` method. – Felipe Oriani May 27 '14 at 14:55

5 Answers5

23

If your view derives from ApiController, you should be able to call the Created method from base class to create such a response.

Sample:

[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);
}
Gildor
  • 2,484
  • 23
  • 35
15

In ASP.NET Core, an IActionResult can be returned. This means you can return a ObjectResult with a 201 status code.

[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 };
}
chris31389
  • 8,414
  • 7
  • 55
  • 66
  • Since 2016, did you encounter swagger and why this is not perfect for it? – Rafael Herscovici Nov 12 '20 at 19:05
  • I think with swagger you can add attributes above the method which tell swagger what return statuses are possible and what the object shape will be – chris31389 Nov 17 '20 at 21:52
  • Perhaps "should" is not the right word here. It "could". You can return actual models or throw exceptions also which is more elegant in many cases. – Jonas Stensved Mar 17 '21 at 15:52
11
return Content(HttpStatusCode.Created, "Message");

Content is returning NegotiatedContentResult. NegotiatedContentResult is implements IHttpActionResult.

enter image description here

enter image description here

A similar problem: If you want to send NotFound with the message.

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

Or:

return Content(HttpStatusCode.Created, Class object);
return Content(HttpStatusCode.NotFound, Class object);
miragessee
  • 313
  • 1
  • 4
  • 14
3

Alternatively, to what Chris is suggesting, what you can do is return an IActionResult, using or "StatusCode" method, the following way:

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

    // Return 201
    return StatusCode(StatusCodes.Status201Created, entity);
}
David Oganov
  • 976
  • 1
  • 11
  • 23
-2

I know this is an old thread but you might want to take a look at my solution here. Its a little more than needed but sure will do the job.

Steps:

Define a custom attribute:

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

Decorate the uniquely identifying property of your model with a custom 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; }
    }

Add a new Created(T yourobject); method to a BaseController which inherits from ApiController. Inherit all your controllers from this 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);
     }

Its pretty simple without having to worry about writing so much in every method. All you got to do is just call Created(yourobject);

The Created() method would still work if you forget to decorate or cannot decorate your model(for some reason). The location header would miss the Id though.

Your unit test for that controller should take care of this.

Community
  • 1
  • 1
Abhishek Tiwari
  • 417
  • 3
  • 14