MVC数据验证Membership使用常见错误
在做注册界面的时候,出现了两个错误,让我纠结得想死,幸好最后都解决了,只能怪自己对MVC的Membership了解得不深,尤其是有关Web.Config的配置问题。
问题一:Membership.IsValid返回为false
这个问题一开始让我很无语,因为在之前也有做过注册界面,但并不会出现这样的问题,代码如下:
[HttpPost] public ActionResult Register(RegisterModel model) { if(ModelState.IsValid) { // Attempt to register the user MembershipCreateStatus createStatus; Membership.CreateUser(model.UserName, model.Password, model.Email, null, null, true, null, out createStatus); if (createStatus == MembershipCreateStatus.Success) { FormsAuthentication.SetAuthCookie(model.UserName, false /* createPersistentCookie */); return RedirectToAction("LogOn", "Account"); } else { ModelState.AddModelError("test", ErrorCodeToString(createStatus)); return RedirectToAction("Index", "Home"); } } // If we got this far, something failed, redisplay form return View(model); }
这是RegisterModel的代码:
public class RegisterModel { [Required(ErrorMessage = "姓名不能为空!")] [Display(Name = "学生名")] [StringLength(160)] public string UserName { get; set; } [Required(ErrorMessage = "密码不能为空!")] [StringLength(160, ErrorMessage = "{0}至少是{2}位数以上!", MinimumLength = 6)] [DataType(DataType.Password)] [Display(Name = "密码")] public string Password { get; set; } [DataType(DataType.Password)] [Display(Name = "确认密码")] [Compare("Password", ErrorMessage = "密码不一致,请重新输入!")] public string ConfirmPassword { get; set; } [Required(ErrorMessage = "电话不能为空!")] [StringLength(160)] [DisplayName("电话")] public String Phone { get; set; } [Required(ErrorMessage = "QQ不能为空!")] [StringLength(160)] [DisplayName("QQ")] public String QQ { get; set; } [Required(ErrorMessage = "邮箱不能为空!")] [StringLength(160)] [RegularExpression(@"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+[A-Za-z]{2,4}", ErrorMessage = "Email is not valid")] [DataType(DataType.EmailAddress)] [DisplayName("电子邮箱")] public String Email { get; set; } [Required(ErrorMessage = "学号不能为空!")] [DisplayName("学号")] [StringLength(160)] public String Number { get; set; } }
然后是我的视图代码:
<div class="editor-label"> <%: Html.LabelFor(model => model.UserName)%> </div> <div class="editor-field"> <%: Html.TextBoxFor(model => model.UserName)%> <%: Html.ValidationMessageFor(model => model.UserName)%> </div> <div class="editor-label"> <%: Html.LabelFor(model => model.Number)%> </div> <div class="editor-field"> <%: Html.TextBoxFor(model => model.Number)%> <%: Html.ValidationMessageFor(model => model.Number)%> </div> <div class="editor-label"> <%: Html.LabelFor(model => model.Password)%> </div> <div class="editor-field"> <%: Html.PasswordFor(model => model.Password)%> <%: Html.ValidationMessageFor(model => model.Password)%> </div> <div class="editor-label"> <%: Html.LabelFor(model => model.ConfirmPassword)%> </div> <div class="editor-field"> <%: Html.PasswordFor(model => model.ConfirmPassword) %> <%: Html.ValidationMessageFor(model => model.ConfirmPassword) %> </div>
如果运行就会出现这样的错误。原因很简单,就是Model所有字段都有Reguired,也就是要求视图验证,但视图中能赋值的只是其中几个值,也就是说,能够验证的值只有视图页显示的那几个,其他要求验证的属性字段就会返回错误信息给ModelState,因为ModelState绑定的是整个Model。
如果只是想要让用户输入几个值而已,可以去掉其他属性字段的Required,否则就要老老实实的在视图页中提供其他属性字段的输入。
问题二:MembershipCreateStatus的值并不等于Success
这个问题涉及到Membership的配置。我们想要使用Membership,必须在我们的Web.config中添加下面的配置代码:
<system.web> <profile defaultProvider="DefaultProfileProvider"> <providers> <add name="DefaultProfileProvider" type="System.Web.Providers.DefaultProfileProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" applicationName="/" /> </providers> </profile> <membership defaultProvider="DefaultMembershipProvider"> <providers> <add name="DefaultMembershipProvider" type="System.Web.Providers.DefaultMembershipProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/" /> </providers> </membership> <roleManager enabled="true" defaultProvider="DefaultRoleProvider"> <providers> <add connectionStringName="DefaultConnection" applicationName="/" name="DefaultRoleProvider" type="System.Web.Providers.DefaultRoleProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /> </providers> </roleManager> <sessionState mode="InProc" customProvider="DefaultSessionProvider"> <providers> <add name="DefaultSessionProvider" type="System.Web.Providers.DefaultSessionStateProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" /> </providers> </sessionState> </system.web/>
如果运行还有错误,说明没有引入System.Web.Providers这个包,需要使用Nuget命令:
Install-Package System.Web.Providers
导入后,问题就解决了。
在解决上面的问题中,我也大概摸索出一些调试方法。
想要获得ModelState某个属性字段的错误信息,可以使用TempData:
TempData["UserName"] = ModelState["UserName"];
然后在视图中添加:
<p> <%= TempData["UserName"] == null ? "" : TempData["UserName"].ToString() %> </p>
ModelState就是错误信息的字典值,只要提供相应的键值就能获得对应的错误信息。TempData有个好处就是它不需要传递给视图就可以直接使用。
同样也可以获得MembershipCreateStatus的错误信息:
TempData["test"] = ErrorCodeToString(createStatus);
我们也可以将错误信息添加进ModelState中:
ModelState.AddModelError("test", ErrorCodeToString(createStatus));
调试代码的第一步就是获得错误信息,连错误信息都得不到,又怎能解决问题呢?这时就要想方设法获得错误信息,然后再进行改正。