【发布时间】:2020-12-17 16:10:08
【问题描述】:
在看到 DB 中的更改后,我不知道如何编辑该行。
- 我有一个 API 项目和一个 MVC 项目。我在我的 API 中使用 CRUD,并使用我的 MVC 和 HttpClient 调用它们
- 我有一个
public byte[] RowVersion { get; set; }属性,属性为[Timestamp]。 - 我有一个 clientFactory,我在其中执行 CreateClient() 以执行
PutAsync("api.example.com/{id}")操作。 - 我的 putasync 操作上的
HttpResponseMessage variable返回StatusCode(409),因为我的 API 成功检测到并发冲突。 - 我设法在更新并发之前显示错误消息;在新客户端
clientFactory.CreateClient()的帮助下显示数据库(newsDb)中新更新的行,并将它们与输入(新闻)进行比较。 - 然后我设置
news.RowVersion = newsDb.RowVersion并重新显示视图(新闻)。
再次单击“保存”后,什么也没有发生 - 没有重定向,没有更改 - 并发错误仍然存在:
[HttpPost("edit/{id}")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> EditNewsArticle(int id, [Bind("NewsId,Author,Title,Content,CreatedDate,HashTags,RowVersion")] News news)
{
if (id != news.NewsId)
{
return NotFound();
}
if (ModelState.IsValid)
{
news.UpdatedDate = DateTime.Now;
string json = JsonConvert.SerializeObject(news);
HttpResponseMessage putTask = await clientFactory.CreateClient().PutAsync($"https://localhost:44331/api/News/{id}", new StringContent(json, Encoding.UTF8, "application/json"));
if (putTask.IsSuccessStatusCode)
{
return RedirectToAction(nameof(Index));
}
else if (putTask.StatusCode == HttpStatusCode.Conflict)
{
string jsonDb = await clientFactory.CreateClient().GetStringAsync($"https://localhost:44331/api/News/{id}");
News newsDb = JsonConvert.DeserializeObject<News>(jsonDb);
if (newsDb is null)
{
ModelState.AddModelError(string.Empty, $"Unfortunately, the news item you edited has already been deleted by another user.");
}
if (newsDb.Title != news.Title)
{
ModelState.AddModelError("Title", $"Title in database: {newsDb.Title}");
}
if (newsDb.Author != news.Author)
{
ModelState.AddModelError("Author", $"Author in database: {newsDb.Author}");
}
if (newsDb.Content != news.Content)
{
ModelState.AddModelError("Content", $"Content in database: {newsDb.Content}");
}
if (newsDb.HashTags != news.HashTags)
{
ModelState.AddModelError("HashTags", $"HashTags in database: {newsDb.HashTags}");
}
ModelState.AddModelError(string.Empty,
"Editing was canceled as the selected news item was changed by someone else in the meantime." +
"The values of the change are now shown below, which are derived from the database" +
"If you still want to edit the user, click Save again.");
news.RowVersion = newsDb.RowVersion;
}
else
{
ModelState.AddModelError(string.Empty, "Unknown error. Contact a support.");
return View(news);
}
}
return View(news);
}
API 放置:
[HttpPut("{id}")]
public async Task<IActionResult> PutNews(int id, [FromBody] News news)
{
if (id != news.NewsId)
{
return BadRequest();
}
context.Entry(news).State = EntityState.Modified;
try
{
await context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!NewsExists(id))
{
return NotFound();
}
else
{
return StatusCode(409);
}
}
return CreatedAtAction("GetNews", new { id = news.NewsId }, news);
}
【问题讨论】:
-
我不认为更新的并发错误是前端的问题,这是API的责任,你可以发布api代码吗?还有,当你点击保存时,网络标签上会创建多少个请求?
-
@MestreDosMagros 我更新了问题并添加了 API httpput 的代码
-
您正在向 ModelState 添加并发错误,并且在第二次保存单击时它们仍然存在并且您的 ModelState 无效。
-
@Quercus 我调试了它,ModelState 仍然有效,并再次进入并发。编辑:我尝试删除 if(ModelState.IsValid)
-
不需要这个:context.Entry(news).State = EntityState.Modified;从 db 获取实体并更新值,然后调用 SaveChanges()
标签: c# asp.net asp.net-web-api concurrency httpclient