web-dev-qa-db-fra.com

Renvoyer un objet avec une erreur de conflit 409 dans une API Web 2 POST appel soutenu par Entity Framework?

J'ai un Framework d'entité C # Contrôleur Web API 2. Actuellement, quand une tentative est faite via la méthode [~ # ~] post [~ # ~] pour créer un objet avec le même texte pour le champ de texte principal, je retourne un 409 Erreur de conflit en tant que résultat StatusCode pour indiquer que l'ajout est considéré comme un doublon.

Ce que je voudrais faire, c'est aussi renvoyer l'objet côté serveur qui a déclenché l'erreur en double. J'ai donc besoin de quelque chose qui ressemble à la méthode Ok () mais une variante qui renvoie une erreur 409 Conflict comme code d'état HTTP au lieu d'un code d'état HTTP OK .

Existe-t-il une telle chose? Comment puis-je faire ceci? Si je peux faire en sorte que cela fonctionne, le client n'a pas besoin d'appeler le serveur Get pour obtenir l'objet existant après avoir reçu une erreur de conflit 409.

Voici la méthode POST actuelle:

    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);
    }
19
Robert Oschler

EDIT: Cette solution est pour WebApi antérieure à la v5, veuillez voir cette réponse si vous utilisez la v5 ou supérieure.

Vous pouvez renvoyer un NegotiatedContentResult<T> qui vous permet de spécifier le code d'état et un objet à placer dans le corps du message http.

Changez votre code en quelque chose comme ceci:

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

Ou peut-être envelopper une méthode d'extension comme celle-ci:

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

Et puis utilisez l'extension comme ceci:

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
Anish Patel

Vous devez renvoyer le contenu:

return Content(HttpStatusCode.Conflict, original);

Content est une méthode sur la classe ApiController qui créera un NegotiatedContentResult avec le HttpStatusCode et le contenu fournis. Il n'est pas nécessaire de créer votre propre méthode d'extension sur la classe ApiController comme dans la réponse acceptée.

19
Kieran

Arrivé ici à la recherche d'aide avec ASP.NET Core HTTP 409 - c'est lié, juste la nouvelle approche pour résoudre ce même problème.

Action de conflit Résultat

 return Conflict(new { message = $"An existing record with the id '{id}' was already found."});
3
SliverNinja - MSFT