2014-11-03 108 views
0

對於當前登錄的用戶,我有一個Manage頁面。該視圖加載兩個部分視圖。一個用於更新用戶註冊的電子郵件地址,另一個用於更新密碼。該Manage視圖看起來像從部分視圖返回的模型字段包含空值

@using VisasysNET.Models; 
@using Microsoft.AspNet.Identity; 
@model VisasysNET.Models.ManageUserViewModel 
@{ 
    ViewBag.Title = "Manage Account"; 
} 

<h2>@ViewBag.Title</h2> 
<p class="text-success">@ViewBag.StatusMessage</p> 
<div class="row"> 
    <div class="col-md-12"> 
     @Html.Partial("_ChangeEmailAddressPartial", Model) 
    </div> 
</div> 
<div class="row"> 
    <div class="col-md-12"> 
     @if (ViewBag.HasLocalPassword) 
     { 
      @Html.Partial("_ChangePasswordPartial") 
     } 
     else 
     { 
      @Html.Partial("_SetPasswordPartial") 
     } 
    </div> 
</div> 
@section Scripts { 
    @Scripts.Render("~/bundles/jqueryval") 
} 

我在更新電子郵件局部視圖有一個「更新電子郵件/密碼」按鈕,分別更新密碼局部視圖。現在,我通過

[HttpPost] 
[ValidateAntiForgeryToken] 
public async Task<ActionResult> Manage(ManageUserViewModel model) 
{ 
    bool hasPassword = HasPassword(); 
    ViewBag.HasLocalPassword = hasPassword; 
    ViewBag.ReturnUrl = Url.Action("Manage"); 
    if (hasPassword) 
    { 
     if (ModelState.IsValid) 
     { 
      IdentityResult result = await UserManager.ChangePasswordAsync(
       User.Identity.GetUserId(), model.OldPassword, model.NewPassword); 
      if (result.Succeeded) 
      { 
       return RedirectToAction("Manage", 
        new { Message = ManageMessageId.ChangePasswordSuccess }); 
      } 
      else 
       AddErrors(result); 
     } 
    } 
    else 
    { 
     // User does not have a password so remove any validation 
     // errors caused by a missing OldPassword field. 
     ... 
    } 
    // If we got this far, something failed, redisplay form. 
    return View(model); 
} 

處理從控制器的管理視圖中的帖子裏

public class ManageUserViewModel 
{ 
    [Required] 
    [EmailAddress(ErrorMessage = "Invalid email address.")] 
    [DataType(DataType.EmailAddress)] 
    [Display(Name = "Email address")] 
    public string EmailAddress { get; set; } 

    [Required] 
    [DataType(DataType.Password)] 
    [Display(Name = "Current password")] 
    public string OldPassword { get; set; } 

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

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

的問題是,如果用戶點擊更新密碼按鈕

<input type="submit" value="Update Password" class="btn btn-primary" /> 

查看,ManageUserViewModel.EmailAddress返回爲空,並且也是相反的(如果用戶單擊「更新電子郵件地址」按鈕,則密碼字段將返回爲空)。這是一個問題,因爲我再拿到驗證錯誤消息

Validation Error

在上面我試圖更新密碼。如果按下「更新密碼」按鈕,我如何防止執行電子郵件驗證,反之亦然?

謝謝你的時間。


請求的局部視圖

電子郵件更新局部視圖是

@using Microsoft.AspNet.Identity 
@model VisasysNET.Models.ManageUserViewModel 
<p>You're logged in as <strong>@User.Identity.GetUserName()</strong></p> 
@using (Html.BeginForm("Manage", "Account", FormMethod.Post, 
    new { @class = "form-horizontal", role = "form" })) 
{ 
    @Html.AntiForgeryToken() 
    <h4>Change Email Address</h4> 
    <hr /> 
    @Html.ValidationSummary() 
    <div class="form-group"> 
     @Html.LabelFor(m => m.EmailAddress, 
      new 
      { 
       @class = "col-md-2 control-label" 
      }) 
     <div class="col-md-10"> 
      @Html.TextBoxFor(m => m.EmailAddress, 
       new 
       { 
        @class = "col-md-10 form-control", 
        @type = "text", 
        @placeholder = "Email Address", 
        @value = Model.EmailAddress 
       }) 
     </div> 
    </div> 
    <div class="form-group"> 
     <div class="col-md-offset-2 col-md-10"> 
      <input type="submit" value="Update Email Address" class="btn btn-primary" /> 
     </div> 
    </div> 
} 

更新密碼部分是

@using Microsoft.AspNet.Identity 
@model VisasysNET.Models.ManageUserViewModel 

@*<p>You're logged in as <strong>@User.Identity.GetUserName()</strong></p>*@ 

@using (Html.BeginForm("Manage", "Account", FormMethod.Post, 
    new { @class = "form-horizontal", role = "form" })) 
{ 
    @Html.AntiForgeryToken() 
    <h4>Change Password</h4> 
    <hr /> 
    @Html.ValidationSummary() 
    <div class="form-group"> 
     @Html.LabelFor(m => m.OldPassword, 
     new { @class = "col-md-2 control-label" }) 
     <div class="col-md-10"> 
      @Html.PasswordFor(m => m.OldPassword, 
      new { @class = "form-control" }) 
     </div> 
    </div> 

    <div class="form-group"> 
     @Html.LabelFor(m => m.NewPassword, 
     new { @class = "col-md-2 control-label" }) 
     <div class="col-md-10"> 
      @Html.PasswordFor(m => m.NewPassword, 
      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" value="Change password" class="btn btn-primary" /> 
     </div> 
    </div> 
} 

編輯#2。在回答問題

GET方法是

// GET: /Account/Manage. 
public ActionResult Manage(ManageMessageId? message) 
{ 
    ViewBag.StatusMessage = 
     message == ManageMessageId.ChangePasswordSuccess ? 
      "Your password has been changed": 
     message == ManageMessageId.SetPasswordSuccess ? 
      "Your password has been set" : 
     message == ManageMessageId.RemoveLoginSuccess ? 
      "The external login was removed" : 
     message == ManageMessageId.ChangeEmailAddressSuccess ? 
      "Your email address was successfully updated" : 
     message == ManageMessageId.Error ? 
      "An error has occurred." : ""; 
    ViewBag.HasLocalPassword = HasPassword(); 
    ViewBag.ReturnUrl = Url.Action("Manage"); 

    // Get current email address. 
    var user = UserManager.FindById(User.Identity.GetUserId()); 
    ManageUserViewModel model = new ManageUserViewModel(); 
    model.EmailAddress = user.EmailAddress; 
    return View(model); 
} 

但有一種觀點似乎知道什麼是OldPassword,它被放置在文本框,這是空明顯,所以這是火狐是聰明?

那麼你是說我應該通過一個object[]包含兩個視圖模型,一個用於密碼,另一個用於電子郵件?

+0

你能後的局部視圖特定的屬性? – dmorganb 2014-11-03 11:29:48

+0

@dmorgan我用部分視圖更新了問題。謝謝你的幫助。 – MoonKnight 2014-11-03 11:37:39

回答

2

我想你會過得更好考慮這些獨立的視圖模型,特別是對於客戶端驗證,但是您可以清除ModelState錯誤使用

if (ModelState.ContainsKey("Email")) 
{ 
    ModelState["Email"].Errors.Clear(); 
} 
+0

感謝您的回覆,非常感謝。我對這裏的最佳做法感到困惑。我已經更新了這個問題。如果你可以進一步建議,這將是可怕的... – MoonKnight 2014-11-03 11:52:26

+0

我不知道你的應用程序的細節,我不使用'身份證',但乍一看,我看到一些問題。首先,您似乎在註冊並使用簡單名稱(「標記」)登錄並添加電子郵件作爲附加屬性。什麼確保登錄名稱是唯一的?爲什麼不用電子郵件登錄,並有一個'友好的顯示名稱'作爲額外的財產?其次,更改電子郵件看起來與更改密碼不同,您可能需要一個單獨的視圖和一個單獨的視圖模型,其中包含現有,新建和確認的字段(通常爲密碼所做)。 – 2014-11-03 21:43:22

+0

快速查看由VS生成的默認'AccountController'和'AccountViewModels',我不確定爲什麼這不適合您的需要(適應添加'顯示名稱')。你似乎正在重新發明輪子,並且在這個過程中,失去了MVC的一些強大功能。例如,你不能使用客戶端驗證;你需要黑客進行服務器端驗證;你有一個潛在的安全問題(雖然馬克得到了一杯咖啡,但他的同事可以改變電子郵件,馬克也不會更聰明) – 2014-11-03 21:56:21