简体   繁体   English

如何处理与 HttpClient 的并发冲突?

[英]How to handle Concurrency Conflicts with HttpClient?

I can't figure out how to edit the row after seeing the changes in DB.在看到数据库中的更改后,我无法弄清楚如何编辑该行。

  • I have an API-project and an MVC-project.我有一个 API 项目和一个 MVC 项目。 I use CRUD in my API and call them with my MVC with HttpClient我在我的 API 中使用 CRUD,并用我的 MVC 和 HttpClient 调用它们
  • I have a public byte[] RowVersion { get; set; }我有一个public byte[] RowVersion { get; set; } public byte[] RowVersion { get; set; } public byte[] RowVersion { get; set; } property with the attribute [Timestamp] . public byte[] RowVersion { get; set; }具有属性[Timestamp]的属性。
  • I have a clientFactory where I do CreateClient() to perform PutAsync("api.example.com/{id}") action.我有一个 clientFactory,我在其中执行 CreateClient() 以执行PutAsync("api.example.com/{id}")操作。
  • The HttpResponseMessage variable on my putasync action returns StatusCode(409) because my API successfully detected a concurrency conflict.我的 putasync 操作上的HttpResponseMessage variable返回StatusCode(409) ,因为我的 API 成功检测到并发冲突。
  • I managed to display error messages before updating the concurrency;我设法在更新并发之前显示错误消息; showing the newly updated rows in the database(newsDb) with help of a new client , clientFactory.CreateClient() , and comparing them with the inputs(news).新客户端clientFactory.CreateClient()的帮助下显示数据库(newsDb)中新更新的行,并将它们与输入(新闻)进行比较。
  • Then I set the news.RowVersion = newsDb.RowVersion and re-display View(news).然后我设置news.RowVersion = newsDb.RowVersion并重新显示 View(news)。

And after clicking Save again, nothing happens - no redirects, no changes - the concurrency errors are still there:再次点击保存后,什么也没有发生——没有重定向,没有更改——并发错误仍然存在:

[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 Put: 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);
}

I found my issue.我发现了我的问题。 I needed to call ModelState.Clear();我需要调用 ModelState.Clear(); after de-serializing the 'jsonDb', and also remove RowVersion from Bind in the attribute.在反序列化“jsonDb”之后,还从属性中的 Bind 中删除 RowVersion。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM