应该为false时,MVC ModelState IsValid报告为true

时间:2014-05-07 16:28:59

标签: c# asp.net-mvc entity-framework validation data-annotations

我有以下3个类(现在包括所有代码)......

using System.ComponentModel.DataAnnotations;

namespace MyWebApp.Models
{
    public class ApplicationUser
    {
        [Display(Prompt = "Your Name", Name = "Contact Name"), Required(), StringLength(255, MinimumLength = 3, ErrorMessage = "Please enter a valid contact")]
        public string ContactName { get; set; }
        [Display(Name = "Username", Prompt = "Login As"), Required(), StringLength(255, MinimumLength = 3, ErrorMessage = "Your username must be at least 3 characters")]
        public string UserName { get; set; }
    }

    public class Account
    {
        [Display(Name = "Account Type", Prompt = "Account Type"), Required()]
        public int AccountType { get; set; }
        [Display(Name = "Organisation Name", Prompt = "Name of Organisation"), StringLength(255)]
        public string OrganisationName { get; set; }
    }

    public class RegisterViewModel
    {
        public ApplicationUser ApplicationUser { get; set; }
        public Account Account { get; set; }

        public RegisterViewModel()
        {
            ApplicationUser = new ApplicationUser();
            Account = new Account();
        }

        [Display(Name = "Password", Prompt = "Password"), Required(), DataType(DataType.Password), StringLength(255, MinimumLength = 5, ErrorMessage = "The password must be at least 7 characters")]
        public string Password { get; set; }

        [Display(Name = "Confirm Password", Prompt = "Confirm Password"), DataType(DataType.Password), Compare("Password", ErrorMessage = "Your confirmation doesn't match...")]
        public string PasswordConfirmation { get; set; }
    }
}

我的控制器看起来像这样......

using System.Web.Mvc;
using MyWebApp.Models;

namespace MyWebApp.Controllers
{
    [Authorize]
    public class AccountController : Controller
    {
        // GET: /Account/
        [AllowAnonymous]
        public ActionResult Register()
        {
            RegisterViewModel mdl = new RegisterViewModel();
            return View(mdl);
        }

        [HttpPost]
        [AllowAnonymous]
        public ActionResult Register([Bind(Include = "Account.AccountType, ApplicationUser.ContactName, ApplicationUser.UserName, Password, Account.OrganisationName, Account.OrganisationRegistrationNumber, Account.AddressLine1, Account.AddressLine2, Account.AddressLine3, Account.City, Account.County, Account.Postcode, ApplicationUser.Email, ApplicationUser.PhoneNumber, PasswordConfirmation")]RegisterViewModel model)
        {
            if (ModelState.IsValid)
            {
                var user = model.ApplicationUser;
                var associatedAccount = model.Account;

                var u1 = Request.Form["ApplicationUser.UserName"];
                if (u1 == user.UserName)
                {
                    // we got it
                    ViewBag.Message = "We got it";
                }
                else
                {
                    // no we didn't
                    ViewBag.Message = "We failed!";
                }
                return View(model);
            }

            // If we got this far, something failed, redisplay form
            return View(model);
        }
    }
}

我的Register.cshtml视图看起来像这样......

@using MyWebApp.Models
@model MyWebApp.Models.RegisterViewModel

@{
    ViewBag.Title = "Register User";
}

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">
        <h4>New Account</h4>
        <hr />
        <p>@ViewBag.Message</p>
        @Html.ValidationSummary(true)
        <div class="col-md-6">
            <div class="form-group">
                @Html.LabelFor(model => model.ApplicationUser.ContactName, new { @class = "control-label col-md-5" })
                <div class="col-md-7">
                    @Html.EditorFor(model => model.ApplicationUser.ContactName, new { @class = "form-control" })
                    @Html.ValidationMessageFor(model => model.ApplicationUser.ContactName)
                </div>
            </div>
            <div class="form-group">
                @Html.LabelFor(model => model.ApplicationUser.UserName, new { @class = "control-label col-md-5" })
                <div class="col-md-7">
                    @Html.EditorFor(model => model.ApplicationUser.UserName, new { @class = "form-control" })
                    @Html.ValidationMessageFor(model => model.ApplicationUser.UserName)
                </div>
            </div>
            <div class="form-group">
                @Html.LabelFor(model => model.Password, new { @class = "control-label col-md-5" })
                <div class="col-md-7">
                    @Html.EditorFor(model => model.Password, new { @class = "form-control" })
                    @Html.ValidationMessageFor(model => model.Password)
                </div>
            </div>
            <div class="form-group">
                @Html.LabelFor(model => model.PasswordConfirmation, new { @class = "control-label col-md-5" })
                <div class="col-md-7">
                    @Html.EditorFor(model => model.PasswordConfirmation, new { @class = "form-control" })
                    @Html.ValidationMessageFor(model => model.PasswordConfirmation)
                </div>
            </div>
        </div>
        <div class="col-md-6">
            <div class="org-info">
                <div class="form-group">
                    @Html.LabelFor(model => model.Account.OrganisationName, new { @class = "control-label col-md-5" })
                    <div class="col-md-7">
                        @Html.EditorFor(model => model.Account.OrganisationName, new { @class = "form-control" })
                        @Html.ValidationMessageFor(model => model.Account.OrganisationName)
                    </div>
                </div>
            </div>
            <hr />
            <div class="form-group">
                <div class="col-md-8"></div>
                <div class="col-md-4">
                    <input type="submit" value="Sign Up" class="btn btn-default form-control" />
                </div>
            </div>
        </div>
    </div>
}

我的问题是,当用户点击注册而不在视图中输入任何详细信息时,只有密码和密码确认字段显示有问题,没有任何帐户或ApplicationUser属性显示问题。

如果我输入密码和确认字段的详细信息并在Register方法中放置一个断点,即使我没有添加任何帐户或用户详细信息,ModelState.IsValid值也为true。

如果我输入说出用户名,评估......

Request.Form["ApplicationUser.UserName"]

给出了正确的值,但我认为应该由Bind填充的ApplicationUser.UserName没有任何内容!?

我怀疑这是我的Bind声明,但我尝试了UserName,ApplicationUser.UserName和ApplicationUser_UserName,但似乎都有同样的问题。

这个问题来自我提出的另一个问题(链接如下),所以我错过了什么?

Entity Framework 6 Reusing Data Annotations

请注意,我对这个特定实现中的错误感兴趣,而不是出于各种原因提供替代实现,我真的不想进入。

3 个答案:

答案 0 :(得分:1)

我已下载您的代码并将其包含在新的空MVC4应用程序中。

坏消息是它没有用。

好消息是它可以通过一个小小的变化完美地运作:

在你的控制器中,

  • 删除Bind POST操作参数
  • Register属性
  • 或使用此项:[Bind(Include = "Account, ApplicationUser, Password, PasswordConfirmation")]

关于你的代码的一对评论:

  • 除非您想明确包含或排除部分模型(通常出于安全原因),否则您不需要使用Bind属性。您宁愿使用所需的确切属性创建一个ViewModel(以这种方式键入和维护更少的代码!)。
  • 您不需要提供默认构造函数来初始化嵌套对象。 MVC模型绑定器将自动实例化它们。实际上,我建议您不要这样做:如果您忘记在视图中包含嵌套对象的属性,则该嵌套对象应为null,而不是具有null属性的对象。这可以产生很多的混淆!!

答案 1 :(得分:0)

尝试在RegisterViewModel中包含ApplicationUser和Account属性。

    public class RegisterViewModel
{
    [Display(Prompt = "Your Name", Name = "Contact Name"), Required(), StringLength(255, MinimumLength = 3, ErrorMessage = "Please enter a valid contact")]
    public string ContactName { get; set; }
    [Display(Name = "Username", Prompt = "Login As"), Required(), StringLength(255, MinimumLength = 3, ErrorMessage = "Your username must be at least 3 characters")]
    public string UserName { get; set; }
[Display(Name = "Account Type", Prompt = "Account Type"), Required()]
    public AccountType AccountType { get; set; }
    [Display(Name = "Organisation Name", Prompt = "Name of Organisation"), StringLength(255)]
    public string OrganisationName { get; set; }
    public RegisterViewModel()
    {

    }

    [Display(Name = "Password", Prompt = "Password"), Required(), DataType(DataType.Password), StringLength(255, MinimumLength = 5, ErrorMessage = "The password must be at least 7 characters")]
    public string Password { get; set; }

    [Display(Name = "Confirm Password", Prompt = "Confirm Password"), Compare("Password", ErrorMessage = "Your confirmation doesn't match...")]
    public string PasswordConfirmation { get; set; }
}

答案 2 :(得分:0)

您可能想要删除构造函数(因为如果它们为null,则需要它们确定)

public RegisterViewModel()
{
    ApplicationUser = new ApplicationUser();
    Account = new Account();
}

并且需要ApplicationUserAccount属性。

验证在绑定期间发生,如果这两个属性都没有绑定,那么您的模型状态将在设计上有效。