ASP.NET MVC + 身份实现 // 模型返回的 ID 与可见的不同

ASP.NET MVC + Identity implementation // Different ID returned with model than what is visible

亲爱的大家,

这是我在 Whosebug 上的第一个 post,所以如果 post 有什么不正确的地方,请指出,以便我进行修改。

问题

我有一个视图,该视图基于以选定的 ApplicationUser 作为成员的已传递模型提供对选定用户的帐户信息的可见性。当我使用按钮发出 HTTPpost 请求时,模型中的每个数据都会被传递,但 ApplicationUser ID 因某种原因发生更改,因此我稍后使用 FindById 进行的 HTTPPost 操作无法正常工作。

型号

public class ModifyAccountModel
{
    public ApplicationUser SelectedUser { get; set; }

    public IEnumerable<string> CurrentRoles { get; set; }

    public IEnumerable<IdentityRole> AvailableRoles { get; set; }
}

风景

@model Time_Window_Management_MVC.Models.ModifyAccountModel
@{
    ViewBag.Title = "Modify Account";
}

<h2>@ViewBag.Title</h2>

@using (Html.BeginForm("ModifyAccount", "Admin", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
{
    @Html.AntiForgeryToken()
    <h4>Attributes</h4>
    <div>
        @ViewBag.Errormessage
    </div>
    @Html.ValidationSummary("", new { @class = "text-danger" })
    <div class="form-group">
        <div class="col-md-2">
            User ID
        </div>
        @*@Html.LabelFor(m => m.FirstName, new { @class = "col-md-2 control-label" })*@
        <div class="col-md-10">
            @Html.DisplayFor(m => m.SelectedUser.Id)
        </div>
    </div>
    <div class="form-group">
        <div class="col-md-2">
            First Name
        </div>
        @*@Html.LabelFor(m => m.FirstName, new { @class = "col-md-2 control-label" })*@
        <div class="col-md-10">
            @Html.TextBoxFor(m => m.SelectedUser.FirstName, new { @class = "form-control" })
        </div>
    </div>
    <div class="form-group">
        <div class="col-md-2">
            Second Name
        </div>
        @*@Html.LabelFor(m => m.SecondName, new { @class = "col-md-2 control-label" })*@
        <div class="col-md-10">
            @Html.TextBoxFor(m => m.SelectedUser.SecondName, new { @class = "form-control" })
        </div>
    </div>
    <div class="form-group">
        <div class="col-md-2">
            Sales Org.
        </div>
        @*@Html.LabelFor(m => m.SecondName, new { @class = "col-md-2 control-label" })*@
        <div class="col-md-10">
            @Html.TextBoxFor(m => m.SelectedUser.SalesOrg, new { @class = "form-control" })
        </div>
    </div>
    <div class="form-group">
        <div class="col-md-2">
            SAP System
        </div>
        @*@Html.LabelFor(m => m.SecondName, new { @class = "col-md-2 control-label" })*@
        <div class="col-md-10">
            @Html.TextBoxFor(m => m.SelectedUser.SAP_System, new { @class = "form-control" })
        </div>
    </div>
    <div class="form-group">
        <div class="col-md-2">
            Email
        </div>
        @*@Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" })*@
        <div class="col-md-10">
            @Html.TextBoxFor(m => m.SelectedUser.Email, new { @class = "form-control" })
        </div>
    </div>
    <h4>Roles</h4>
    <table class="table">
        <tr>
            <td>
                Role name
            </td>
            <td>
                Actions
            </td>
        </tr>
        @if (Model.CurrentRoles.Count() == 0)
        {
            <tr>
                @Html.ActionLink("Add new role", "AddAccountRole", new { Id = Model.SelectedUser.Id })
            </tr>
        }
        else
        {
            foreach (var role in Model.CurrentRoles)
            {
                <tr>
                    <td>
                        @role
                    </td>
                    <td>
                        @Html.ActionLink("Delete", "DeleteAccountRole", new { Id = Model.SelectedUser.Id, Role = @role })
                    </td>
                </tr>
            }
            <tr>
                @Html.ActionLink("Add new role", "AddAccountRole", new { Id = Model.SelectedUser.Id })
            </tr>
        }
    </table>

    <div class="form-group">
        <div class="col-md-12">
            <input type="submit" class="btn btn-default" value="Save changes" />
        </div>
    </div>
}

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

响应post请求的动作

[HttpPost]
    public async Task<ActionResult> ModifyAccount(ModifyAccountModel model)
    {
        if (ModelState.IsValid)
        {
            ApplicationUser account = await UserManager.FindByIdAsync(model.SelectedUser.Id);

            if (account == null)
            {
                return RedirectToAction("ManageAccounts", "Admin", "Account modification couldn't be done.");
            }

            account.FirstName = model.SelectedUser.FirstName;
            account.SecondName = model.SelectedUser.SecondName;
            account.SalesOrg = model.SelectedUser.SalesOrg;
            account.SAP_System = model.SelectedUser.SAP_System;

            return RedirectToAction("ModifyAccount", "Admin", new { id = model.SelectedUser.Id });

        }

        return RedirectToAction("ManageAccounts", "Admin", "Something went wrong.");

    }

模型中唯一发生变化的是 ApplicationUser ID,一切都保持原样。

我知道,作为一种解决方法,我可以创建一个仅将 ID 作为字符串发送的操作,然后基于该操作执行 FindByIdAsync 搜索,但我仍然想知道导致此问题的原因。

我怀疑当 posting 的内容与原来的相同时,会创建一个新的 ApplicationUser,因此会创建一个新的 ID,但我想就事.

非常感谢您的任何反馈,祝您有愉快的一天!

丹尼尔

美好的一天,在这条线上

@Html.DisplayFor(m => m.SelectedUser.Id)

只会将当前 userId 的 int 呈现为 html string

它不会包含在您的 post 请求中,然后在您的服务器上 the Binding 每次都会使用 a new GUID 创建新的 ApplicationUser。 尝试简单地将其更改为

@Html.TextBoxFor(m => m.SelectedUser.Id)

将生成 html input(具有 Name 属性)

您可以使用 @Html.HiddenFor(m => m.SelectedUser.Id) 例如。或者,如 RizkiDPrast 所写,@Html.TextBoxFor(m => m.SelectedUser.Id), new { @readonly = true }) 具有只读属性。