在Entity Framework支持的Web API 2 POST调用中返回一个对象以及409 Conflict错误?

我有一个C#Entity Framework Web API 2控制器 。 目前,当通过POST方法尝试创建具有相同文本的主文本字段的对象时,我返回409 Conflict错误作为StatusCode结果,以指示添加被视为重复。

我想做的是返回触发重复错误的服务器端对象。 所以我需要一些类似于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); } 

编辑:此解决方案适用于v5之前的WebApi,如果您使用的是v5或更高版本,请查看此答案 。

您可以返回NegotiatedContentResult ,它允许您指定状态代码和要放入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(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(this ApiController @this, HttpStatusCode statusCode, T content) { return new NegotiatedContentResult(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); } 

你应该退回内容:

 return Content(HttpStatusCode.Conflict, original); 

ContentApiController类的方法,它将使用提供的ApiController和内容创建NegotiatedContentResult 。 无需像在接受的答案中那样在ApiController类上创建自己的扩展方法。

到了这里寻找ASP.NET Core HTTP 409的帮助 – 这是相关的,只是解决同样问题的新方法。

冲突行动结果

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

我有一个与ASP.NET Core 1.0 RC2类似的问题,但我遇到了DbUpdateConcurrencyException ,使用乐观并发我不想让我的用户更新已经更新的对象。

我还想将更新的对象返回给拨打电话的用户。 我能够创建一个新的CreatedAtAction并将StatusCode设置为StatusCodes.Status409Conflict

 context.Entry(user).State = EntityState.Modified; try { await context.SaveChangesAsync(); } catch (DbUpdateConcurrencyException) { if (!UserExists(id)) { return NotFound(); } else { //remove the user we just added, otherwise it will not goto //the database to obtain the updated user context.Entry(user).State = EntityState.Detached; var updatedUser = await context.Users.SingleOrDefaultAsync(m => m.Id == id); if (updatedUser == null) { return NotFound(); } var returnAction = CreatedAtAction("PutUser", new { id = user.Id }, updatedUser); returnAction.StatusCode = StatusCodes.Status409Conflict; return returnAction; } }