在做注冊界面的時候,出現了兩個錯誤,讓我糾結得想死,幸好最后都解決了,只能怪自己對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));
調試代碼的第一步就是獲得錯誤信息,連錯誤信息都得不到,又怎能解決問題呢?這時就要想方設法獲得錯誤信息,然后再進行改正。