web-dev-qa-db-ja.com

Web API 2で409 Conflictエラーとともにオブジェクトを返しますPOST Entity Frameworkによってサポートされる呼び出し?

C#エンティティフレームワークWeb API 2コントローラーがあります。現在[〜#〜] post [〜#〜]メソッドを介してメインテキストフィールドに同じテキストを持つオブジェクトを作成しようとすると、409競合errorStatusCode結果として、追加が重複と見なされることを示します。

私がやりたいのは、重複エラーをトリガーしたサーバー側オブジェクトも返すことです。したがって、Ok()メソッドに似たものが必要ですが、代わりに409 ConflictエラーをHTTPステータスコードとして返すバリアントHTTP OKステータスコード

そんなことありますか?これどうやってするの?これを機能させることができれば、クライアントは409 Conflictエラーを受け取った後、既存のオブジェクトを取得するためにサーバーへの後続のGet呼び出しを行う必要はありません。

これが現在のPOSTメソッドです:

    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

編集:このソリューションはWebApi以前のv5向けです。v5以上を使用している場合は this answer を参照してください。

NegotiatedContentResult<T>を返すと、ステータスメッセージと、httpメッセージ本文に挿入するオブジェクトを指定できます。

コードを次のように変更します。

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

または、次のような拡張メソッドをラップすることもできます。

public static class HttpActionResultExtensions {
    public static IHttpActionResult StatusCodeWithContent<T>(this ApiController @this, HttpStatusCode statusCode, T content) {
        return new NegotiatedContentResult<T>(statusCode, content, @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
Anish Patel

コンテンツを返す必要があります:

return Content(HttpStatusCode.Conflict, original);

ContentApiControllerクラスのメソッドであり、提供されたNegotiatedContentResultとコンテンツを使用してHttpStatusCodeを作成します。受け入れられた回答のように、ApiControllerクラスに独自の拡張メソッドを作成する必要はありません。

19
Kieran

ASP.NET Core HTTP 409のヘルプを探してここに到着しました-これは関連しており、この同じ問題を解決するための新しいアプローチです。

競合ActionResult

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