在实体框架支持的Web API 2 POST调用中返回一个对象和一个409冲突错误
本文关键字:一个对象 错误 冲突 一个 返回 支持 框架 实体 Web API 调用 | 更新日期: 2023-09-27 18:06:49
我有一个c#实体框架Web API 2控制器。目前,当尝试通过POST方法为主文本字段创建具有相同文本的对象时,我返回409冲突错误作为StatusCode结果,以表明添加被认为是重复的。
我想做的是返回触发重复错误的服务器端对象。因此,我需要类似于Ok()方法的东西,但返回409冲突错误作为HTTP状态码而不是HTTP Ok状态码的变体。
有这样的事吗?我该怎么做呢?如果我能使这个工作的客户端不需要做一个后续的Get调用到服务器得到一个409冲突错误后,现有的对象。
下面是当前的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);
}
你应该返回Content:
return Content(HttpStatusCode.Conflict, original);
Content
是ApiController
类上的方法,它将用提供的HttpStatusCode
和内容创建一个NegotiatedContentResult
。不需要在ApiController类上创建自己的扩展方法,就像在接受的答案中那样。
来这里寻求ASP的帮助。. NET Core HTTP 409 -这是相关的,只是解决相同问题的新方法。
冲突ActionResult
return Conflict(new { message = $"An existing record with the id '{id}' was already found."});
编辑:此解决方案适用于WebApi v5之前的版本,如果您使用的是v5或更高版本,请参阅此答案。
你可以返回一个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);
}
我在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;
}
}