Return an object along with a 409 Conflict error in a Web API 2 POST call backed by Entity Framework?

asp.net-mvc asp.net-web-api2 c# entity-framework-6

Question

I have a C# Entity Framework Web API 2 controller. Currently when an attempt is made via the POST method to create an object with the same text for the main text field, I return a 409 Conflict error as an StatusCode result to indicate the addition is considered a duplicate.

What I'd like to do is return the server side object that triggered the duplicate error too. So I need something akin to the Ok() method but a variant that returns a 409 Conflict error as the HTTP status code instead of an HTTP OK status code.

Is there such a thing? How can I do this? If I can make this work the client doesn't have to do a subsequent Get call to the server to get the existing object after receiving a 409 Conflict error.

Here's the current POST method:

    public IHttpActionResult PostCanonical(Canonical canonical)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        // Check for duplicate Canonical text for the same app name.
        if (db.IsDuplicateCanonical(canonical.AppName, canonical.Text))
        {
            // It's a duplicate.  Return an HTTP 409 Conflict error to let the client know.
            return StatusCode(HttpStatusCode.Conflict);
        }

        db.CanonicalSentences.Add(canonical);
        db.SaveChanges();

        return CreatedAtRoute("DefaultApi", new { id = canonical.ID }, canonical);
    }
1
19
8/6/2015 9:50:43 PM

Accepted Answer

EDIT: This solution is for WebApi prior v5, please see this answer if you are using v5 or above.

You could return a NegotiatedContentResult<T> that lets you specify the status code and an object to be put into the http message body.

Change your code to something like this:

public IHttpActionResult PostCanonical(Canonical canonical)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

    // Check for duplicate Canonical text for the same app name.
    if (db.IsDuplicateCanonical(canonical.AppName, canonical.Text))
    {
        // It's a duplicate.  Return an HTTP 409 Conflict error to let the client know.
        var original = db.CanonicalSentences.First(c => c.ID == canonical.ID);
        return new NegotiatedContentResult<T>(HttpStatusCode.Conflict, original, this);
    }

    db.CanonicalSentences.Add(canonical);
    db.SaveChanges();

    return CreatedAtRoute("DefaultApi", new { id = canonical.ID }, canonical);
}

Or maybe wrap it an extension method like this:

public static class HttpActionResultExtensions {
    public static IHttpActionResult StatusCodeWithContent<T>(this ApiController @this, HttpStatusCode statusCode, T content) {
        return new NegotiatedContentResult<T>(statusCode, content, @this);
    }
}

And then use the extension like this:

public IHttpActionResult PostCanonical(Canonical canonical)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

    // Check for duplicate Canonical text for the same app name.
    if (db.IsDuplicateCanonical(canonical.AppName, canonical.Text))
    {
        // It's a duplicate.  Return an HTTP 409 Conflict error to let the client know.
        var original = db.CanonicalSentences.First(c => c.ID == canonical.ID);
        return StatusCodeWithContent(HttpStatusCode.Conflict, original)
    }

    db.CanonicalSentences.Add(canonical);
    db.SaveChanges();

    return CreatedAtRoute("DefaultApi", new { id = canonical.ID }, canonical);
}
14
11/2/2017 9:01:00 AM

Popular Answer

You should return Content:

return Content(HttpStatusCode.Conflict, original);

Content is method on the ApiController class which will create a NegotiatedContentResult with the provided HttpStatusCode and content. There is no need to create your own extension method on the ApiController class like in the accepted answer.



Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow