意外的模型绑定

时间:2018-06-27 05:51:57

标签: c# asp.net asp.net-mvc asp.net-mvc-5

通过带有个人帐户身份验证的支架式MVC 5模板,我偶然发现了一种我无法理解的行为。

提供请求网址

http://localhost:53487/Account/ResetPassword?userId=4&code=T634Hfv%2BxMAlo2XjdLV6a%2Bd1%2BxGsfdiQiKRW0Nh2fB3I1U3S%2BNdXU4ixHC9uJ5F5PSRMZkQgV907CDH0x3aQPSdFliXJqD7nrjk3TLnOTawPeO8CJjk5OEyYijVur1i1Fr7DE7nmaDD93I000fXbQA%3D%3D

AccountController

中的操作方法
[AllowAnonymous]
public ActionResult ResetPassword(string code)
{
    return code == null ? View("Error") : View();
}

和视图ResetPassword.cshtml

@model OPLA.Web.Models.ResetPasswordViewModel
@{
    ViewBag.Title = "Reset password";
}

<h2>@ViewBag.Title.</h2>

@using (Html.BeginForm("ResetPassword", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
{
    @Html.AntiForgeryToken()
    <h4>Reset your password.</h4>
    <hr />
    @Html.ValidationSummary("", new { @class = "text-danger" })    
    @Html.HiddenFor(model => model.Code)
    <div class="form-group">
        @Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" })
        <div class="col-md-10">
            @Html.TextBoxFor(m => m.Email, new { @class = "form-control" })
        </div>
    </div>
    <div class="form-group">
        @Html.LabelFor(m => m.Password, new { @class = "col-md-2 control-label" })
        <div class="col-md-10">
            @Html.PasswordFor(m => m.Password, new { @class = "form-control" })
        </div>
    </div>
    <div class="form-group">
        @Html.LabelFor(m => m.ConfirmPassword, new { @class = "col-md-2 control-label" })
        <div class="col-md-10">
            @Html.PasswordFor(m => m.ConfirmPassword, new { @class = "form-control" })
        </div>
    </div>
    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" class="btn btn-default" value="Reset" />
        </div>
    </div>
}

和viewmodel ResetPasswordViewModel

public class ResetPasswordViewModel
{
    [Required]
    [EmailAddress]
    [Display(Name = "Email")]
    public string Email { get; set; }

    [Required]
    [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
    [DataType(DataType.Password)]
    [Display(Name = "Password")]
    public string Password { get; set; }

    [DataType(DataType.Password)]
    [Display(Name = "Confirm password")]
    [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
    public string ConfirmPassword { get; set; }

    public string Code { get; set; }
}

加载视图时,行@Html.HiddenFor(model => model.Code)会生成此html输出,并正确填充/绑定了viewmodel的Code属性:

<input id="Code" name="Code" type="hidden" value="T634Hfv+xMAlo2XjdLV6a+d1+xGsfdiQiKRW0Nh2fB3I1U3S+NdXU4ixHC9uJ5F5PSRMZkQgV907CDH0x3aQPSdFliXJqD7nrjk3TLnOTawPeO8CJjk5OEyYijVur1i1Fr7DE7nmaDD93I000fXbQA==">

模型绑定程序如何知道code查询字符串参数属于视图模型的Code属性并自动绑定它?

1 个答案:

答案 0 :(得分:4)

您的方法中有一个名为code的参数。执行该方法时,会将code的值添加到ModelState中。

您的模型还具有一个名为Code的属性。您的视图使用@Html.HiddenFor()为该属性生成一个<input>。所有生成表单控件的HtmlHelper方法(PasswordFor()除外)都通过按以下顺序读取值来确定value的{​​{1}}

  1. <input>
  2. ModelState
  3. 属性的实际值

由于ViewDataDictionary包含ModelState的值(不区分大小写),因此code是通过方法参数(即查询字符串值)设置的。

要详细了解为什么此行为是设计使然,请参阅TextBoxFor displaying initial value, not the value updated from code的第二部分。