【问题标题】:Unexpected model binding意外的模型绑定
【发布时间】:2018-06-27 05:51:57
【问题描述】:

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

给定一个请求 url

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>
}

和视图模型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 =&gt; model.Code) 行会生成此 html 输出,其中视图模型的 Code 属性已正确填充/绑定:

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

模型绑定器是如何知道code查询字符串参数属于viewmodel的Code属性并自动绑定的?

【问题讨论】:

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


    【解决方案1】:

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

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

    1. ModelState
    2. ViewDataDictionary
    3. 房产的实际价值

    因为ModelState 包含code 的值(不区分大小写),所以value 是从方法参数(即查询字符串值)中设置的。

    有关为什么这种行为是设计使然的更详细说明,请参阅TextBoxFor displaying initial value, not the value updated from code 的第二部分。

    【讨论】:

    • 感谢斯蒂芬,在通过链接答案了解此行为背后的原因之后,这是有道理的。我很好奇您是如何知道这种行为的,是否有任何文章/文档?
    • 从未见过任何官方文档,但有一篇 MVC 团队成员(我认为是 Brad Wilson?)写的一篇文章讨论了从 MVC-2 到 MVC- 的变化3(它现在已经很旧了,我认为我没有保留书签,但我会看看今天晚些时候有时间能不能找到它)
    • 在对@Stephen Muecke 进行了一番谷歌搜索之后,从 Rick Strahl 那里找到了一个 post
    • This article 是我所指的那个(实际上是 MVC-1 到 MVC-2 的变化)。如果您通过source code 工作,您会看到设置value 属性的优先级
    • 感谢您不厌其烦地挖掘帖子:)
    猜你喜欢
    • 2012-03-13
    • 1970-01-01
    • 2020-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多