簡體   English   中英

當模型屬性具有 [ConcurrencyCheck] 屬性時,ASP.NET Core MVC ConcurrencyCheck 失敗

[英]ASP.NET Core MVC ConcurrencyCheck is failing when the model property has the [ConcurrencyCheck] attribute

我是 ASP.NET Core MVC 中的並發檢查的新手,必須在這里實現錯誤,但是 Microsoft 文檔似乎很薄弱。 有人能指出我正確的方向嗎?

這是一個簡單的用戶類,可由管理員編輯。 如果沒有任何並發​​檢查,表單更改將毫無問題地保存到數據庫中,但是,當我將 [ConcurrencyCheck] 屬性添加到模型屬性之一時,即使字段值發生更改,保存到數據庫也會失敗(我是期望這只會在用戶 A 在用戶 B 之前更新字段時失敗,等等)

任何幫助將不勝感激。

這里有一些片段。

模型

public class MyUser : IdentityUser
    {
        [ConcurrencyCheck]
        [PersonalData]
        [DisplayName("First Name")]
        [Column(TypeName = "nvarchar(100)")]
        public string FirstName { get; set; }

        [PersonalData]
        [DisplayName("Last Name")]
        [Column(TypeName = "nvarchar(100)")]
        public string LastName { get; set; }


        [DisplayName("Created Date")]
        [Column(TypeName = "DateTime")]
        public DateTime CreatedDateTime { get; set; }

        [DisplayName("Customer ID")]
        [Column(TypeName = "int")]
        public int CustomerId { get; set; }


        public string GetFullName()
        {
            return $"{FirstName} {LastName}";
        }

    }

控制器


 // GET: UserController/Edit/5
        public ActionResult Edit(string id)
        {
            // New user view model.
            UserViewModel userViewModel = new UserViewModel();

            // Get user details.
            MyUser user = _context.Users.Where(u => u.Id == id).Single();


           var roles = _context.UserRoles.Where(r => r.UserId == id).ToList();

            if (user != null)
            {
                // Set viewmodel user with user details.
                userViewModel.thisUser = user;

               // userViewModel.thisUserRoles = _context.UserRoles.Where()

                // Get roles assigned to the user.
                //userViewModel.thisUserRoles = _context.userRoles.Where(r => r.UserId == id).ToList();

                // Set viewmodel variables based on which roles the user has.
                if (roles.Count > 0)
                {
                    foreach(var role in roles)
                    {
                        switch (_context.Roles.Where(r => r.Id == role.RoleId).Select(r => r.Name).Single().ToString())
                        {
                            case "User":
                                userViewModel.UserRole = true;
                                break;
                            case "Sales User":
                                userViewModel.SalesUserRole = true;
                                break;
                            case "Sales Branch User":
                                userViewModel.SalesBranchUserRole = true;
                                break;
                            case "Sales Administrator":
                                userViewModel.SalesAdministrator = true;
                                break;
                            case "Administrator":
                                userViewModel.Administrator = true;
                                break;
                                    
                        }
                    }
                }

                return View(userViewModel);
            }
            else
            {
                ViewBag.ErrorMessage = "The user could not be found.";
                return RedirectToAction("Index");
            }
            
        }






 // POST: UserController/Edit/5
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit(UserViewModel userViewModel)
        {

            if (ModelState.IsValid)
            {
                userViewModel.thisUser.UserName = userViewModel.thisUser.Email;
                userViewModel.thisUser.NormalizedUserName = userViewModel.thisUser.Email.ToUpper();
                userViewModel.thisUser.NormalizedEmail = userViewModel.thisUser.Email.ToUpper();


                try
                {

                    _context.Entry(userViewModel.thisUser).State = EntityState.Modified;
                    _context.SaveChanges();

                }
                catch (Exception ex)
                {
                    // Prompt the user to try again.
                    ModelState.AddModelError("", "The information has been updated by someone else before you saved. Please try again.");
                    return View(userViewModel);

                }





            }

            return RedirectToAction("Index");

        }

看法

@model MyApp.ViewModels.UserViewModel

@{
    ViewData["Title"] = "Edit";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

@*<h1>Edit</h1>*@



@*<h5>
    Details
</h5>
<hr />*@

<div class="row">
    <div class="col-md-4">
        <form asp-action="Edit">
            <div asp-validation-summary="All" class="text-danger"></div>


            @Html.HiddenFor(m => m.thisUser.Id)
            @Html.HiddenFor(m => m.thisUser.PasswordHash)
            @Html.HiddenFor(m => m.thisUser.LockoutEnd)
            @Html.HiddenFor(m => m.thisUser.LockoutEnabled)
            @Html.HiddenFor(m => m.thisUser.AccessFailedCount)
            @Html.HiddenFor(m => m.thisUser.CreatedDateTime)
            @Html.HiddenFor(m => m.thisUser.SecurityStamp)
            @Html.HiddenFor(m => m.thisUser.ConcurrencyStamp)
            @Html.HiddenFor(m => m.thisUser.EmailConfirmed)
            <div class="form-group">
                <label asp-for="thisUser.FirstName" class="control-label"></label>
                <input asp-for="thisUser.FirstName" class="form-control" />
                <span asp-validation-for="thisUser.FirstName" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="thisUser.LastName" class="control-label"></label>
                <input asp-for="thisUser.LastName" class="form-control" />
                <span asp-validation-for="thisUser.LastName" class="text-danger"></span>
            </div>




            <div class="form-group">
                <label asp-for="thisUser.Email" class="control-label"></label>
                <input asp-for="thisUser.Email" class="form-control" />
                <span asp-validation-for="thisUser.Email" class="text-danger"></span>
            </div>
           
            <div class="form-group">
                <label asp-for="thisUser.PhoneNumber" class="control-label"></label>
                <input asp-for="thisUser.PhoneNumber" class="form-control" />
                <span asp-validation-for="thisUser.PhoneNumber" class="text-danger"></span>
            </div>
            <div class="form-group form-check">
                <label class="form-check-label">
                    <input class="form-check-input" asp-for="thisUser.PhoneNumberConfirmed" /> @Html.DisplayNameFor(model => model.thisUser.PhoneNumberConfirmed)
                </label>
            </div>
            <div class="form-group form-check">
                <label class="form-check-label">
                    <input class="form-check-input" asp-for="thisUser.TwoFactorEnabled" /> @Html.DisplayNameFor(model => model.thisUser.TwoFactorEnabled)
                </label>
            </div>

            <div class="form-group">
                <label asp-for="thisUser.CustomerId" class="control-label"></label>
                <input asp-for="thisUser.CustomerId" class="form-control" />
                <span asp-validation-for="thisUser.CustomerId" class="text-danger"></span>
            </div>



            <h5>
                Roles
            </h5>
            <hr />

            <div class="form-group form-check">
                <label class="form-check-label">
                    <input class="form-check-input" asp-for="UserRole" /> @Html.DisplayNameFor(model => model.UserRole)
                </label>
            </div>

            <div class="form-group form-check">
                <label class="form-check-label">
                    <input class="form-check-input" asp-for="SalesUserRole" /> @Html.DisplayNameFor(model => model.SalesUserRole)
                </label>
            </div>

            <div class="form-group form-check">
                <label class="form-check-label">
                    <input class="form-check-input" asp-for="SalesBranchUserRole" /> @Html.DisplayNameFor(model => model.SalesBranchUserRole)
                </label>
            </div>

            <div class="form-group form-check">
                <label class="form-check-label">
                    <input class="form-check-input" asp-for="SalesAdministrator" /> @Html.DisplayNameFor(model => model.SalesAdministrator)
                </label>
            </div>

            <div class="form-group form-check">
                <label class="form-check-label">
                    <input class="form-check-input" asp-for="Administrator" /> @Html.DisplayNameFor(model => model.Administrator)
                </label>
            </div>



            <div class="form-group">
                <input type="submit" value="Save" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>

<div>
    <a asp-action="Index">Back to List</a>
</div>

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

根據ms官方文檔,推薦使用row version處理並發沖突

從文檔中總結,我們需要添加一個名為“RowVersion”的列,其數據類型為“rowversion”,並將其添加到您的實體中。

    [Timestamp]
    public byte[] RowVersion { get; set; }

在此處輸入圖片說明

接下來,在調用await _context.SaveChangesAsync();之前await _context.SaveChangesAsync(); 我們需要將原始 RowVersion 屬性值放在實體的 OriginalValues 集合中

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> EditAsync(UserViewModel userViewModel)
{
     if (ModelState.IsValid)
     {
         try
         {
               _context.Entry(userViewModel.thisUser).Property("RowVersion").OriginalValue = userViewModel.thisUser.RowVersion;
               _context.Update(userViewModel.thisUser);
               await _context.SaveChangesAsync();
          }
          catch (Exception ex)
          {
                    // Prompt the user to try again.
              ModelState.AddModelError("", "The information has been updated by someone else before you saved. Please try again.");
              return View(userViewModel);

          }
     }

     return RedirectToAction("Index");
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM