2012-11-09 50 views
0

我在设置MVC 3体系结构中的一些嵌套视图时遇到了问题。这是我目前有:MVC 3问题中的嵌套视图

_Layout.cshtml 
    Logon.cshtml 
     Login.cshtml 
     ForgotPassword.cshtml 

所以基本上,我有我的_Layout.cshtml页面,只是我的母版页。然后我有Logon.cshtml。这充当我的登录页面的“母版页”。在那之下,我有两个部分视图,Login.cshtml和ForgotPassword.cshtml。在所有这些背后,我有一个名为AccountController的控制器。首先,让我告诉你Logon.cshtml

查看/帐号/ Logon.cshtml

@model Coltrane.Web.Website.Models.Account.LogonViewModel 
@{ 
    Layout = "~/Views/Shared/_Layout.cshtml"; 
    ViewBag.Title = "Logon"; 
} 
@*@this.CssIncludes(@Url.Content("~/Content/login.css"))*@ 
@this.ScriptIncludes(@Url.Content("~/Content/scripts/Account/logon.js")) 
@this.InitFunctionIncludes("lga_loginTabs.init()") 
@this.InitFunctionIncludes("lga_formFocus.init()") 
<div id="container"> 
    <div class="sectionFocus noBg"> 
     <div style="margin: 24px auto; width: 450px;"> 
      <div class="customerLogo" style="margin: 24px auto;"> 
       logo 
      </div> 
      <div id="tabContainer" style="position: relative; width:100%;"> 
       <div id="login" class="box_c" style="position:absolute; width:100%;"> 
        <h1>User Login</h1> 
        <div class="box_c_content"> 
         <div class="sepH_c"> 
          @{ Html.RenderAction("Login", "Account"); } 
          <a href="#" id="gotoFogot">Forgot your password?</a> 
         </div> 
        </div> 
       </div> 
       <div id="forgot" class="box_c" style="position: absolute; width:100%;display: none;"> 
        <h1>Forgot Your Password?</h1> 
        <div class="box_c_content"> 
         <div class="sepH_c"> 
          @{ Html.RenderAction("ForgotPassword", "Account"); } 
          <a href="#" id="gotoLogin">Back to Login</a> 
         </div> 
        </div> 
       </div> 
      </div> 
     </div> 
    </div> 
</div> 

请注意,我有渲染登录和ForgotPassword与Html.RenderAction部分景色。我这样做是因为这些实际上都是表单,他们需要发布到AccountController。接下来,让我告诉你我的Login.cshtml文件:

查看/帐号/ Login.cshtml

@model Coltrane.Web.Website.Models.Account.LoginViewModel 
@{ 
    Layout = null; 
} 
@this.ScriptIncludes(@Url.Content("~/Content/scripts/Account/login.js")) 
@this.InitFunctionIncludes("login.init()") 
<div class="sepH_a"> 
    <label> 
     Please enter your email and password to log into the system.</label> 
</div> 
@using (Html.BeginForm("Login", "Account", FormMethod.Post, new { id = "form_login" })) 
{ 
    <div class="sepH_a"> 
     <div class="loginError"> 
      @Html.ValidationSummary(true, "Login was unsuccessful. Please correct the errors and try again.") 
      @Html.ValidationMessageFor(m => m.UserName)<br /> 
      @Html.ValidationMessageFor(m => m.Password) 
     </div> 
    </div> 
    <div class="sepH_a"> 
     @Html.LabelFor(m => m.UserName, new { @class = "lbl_a" }) 
     <br /> 
     @Html.TextBoxFor(m => m.UserName, new { @class = "inpt_a_login", id = "lusername", name = "lusername" }) 
     <span class="inputReqd" style="visibility: visible;">*</span> 
    </div> 
    <div class="sepH_a"> 
     @Html.LabelFor(m => m.Password, new { @class = "lbl_a" }) 
     <br /> 
     @Html.PasswordFor(m => m.Password, new { @class = "inpt_a_login", id = "lpassword", name = "lpassword" }) 
     <span class="inputReqd" style="visibility: visible;">*</span> 
    </div> 
    <div class="sepH_a"> 
     @Html.CheckBoxFor(m => m.RememberMe, new { @class = "input_c", id = "remember" }) 
     @Html.LabelFor(m => m.RememberMe, new { @class = "lbl_c" }) 
    </div> 

    <div class="box_c_footer"> 
     <button class="sectB btn_a" type="submit"> 
      Login</button> 
    </div> 
} 

正如你所看到的,这只是一个简单的形式。有一点需要注意的是,我试图在这里使用两种模型。每个观点一个。一个用于父视图,另一个用于两个子视图(忘记密码也有一个)。不管怎么说,让我告诉你我的AccountController

控制器/ AccountController.cs

public class AccountController : Controller 
    { 
     private IAuthenticationService _authenticationService; 
     private ILoggingService _loggingService; 

     public AccountController(IAuthenticationService authenticationService, 
      ILoggingService loggingService) 
     { 
      _authenticationService = authenticationService; 
      _loggingService = loggingService; 
     } 

     public ActionResult Logon() 
     { 
      return View(); 
     } 

     [HttpGet] 
     [ChildActionOnly] 
     public ActionResult Login() 
     { 
      return PartialView(); 
     } 

     [HttpPost] 
     public ActionResult Login(LoginViewModel model, string returnUrl) 
     { 
      if (ModelState.IsValid) 
      { 
       if (Membership.ValidateUser(model.UserName, model.Password)) 
       { 
        FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe); 
        if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/") 
         && !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\")) 
        { 
         return Redirect(returnUrl); 
        } 
        else 
        { 
         return RedirectToAction("Index", "Home"); 
        } 
       } 
       else 
       { 
        ModelState.AddModelError("", "The user name or password provided is incorrect."); 
       } 
      } 
      else 
      { 
       ModelState.AddModelError("", "An error has occurred."); 
      } 

      // If we got this far, something failed, redisplay form 
      return View("Logon"); 
      // return View(model) 
      // return RedirectToAction("Index", "Home"); 
     } 
     //........ 
    } 

在方法[HttpPost]登录(...),我检查,看看用户是否creds是正确的。如果是这样,一切正常,但问题出在一个错误。如果我使用return View("Logon");我认为我得到一个无限循环,如果我使用return View(model)我获得了Login.cshtml的部分视图,并且如果使用return RedirectToAction("Index", "Home");,我会正确返回到我的登录视图,但我添加的错误是我不知道如何使它正常工作,我想返回呈现登录。我想我的设置是有意义的,但我不知道如何使它正常工作。 ,与错误CSHTML视图只要是完整的,这里有我的两个的ViewModels为提供浏览:

public class LogonViewModel 
{ 
} 

public class LoginViewModel 
{ 
    [Required] 
    [Display(Name = "Email")] 
    public string UserName { get; set; } 

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

    [Display(Name = "Remember Me?")] 
    public bool RememberMe { get; set; } 
} 

回答

2

在我看来,以处理这将是回重定向到索引页面的最佳方式,但你。提及,这会导致你的错误丢失。

虽然有一个很好的解决方案 - 将模型状态保存在TempData中,并将其重新导入索引页面。下面是为您提供可以使用,使这个美丽的无缝几个不错的属性链接:[ImportModelStateFromTempData][ExportModelStateToTempData]

http://weblogs.asp.net/rashid/archive/2009/04/01/asp-net-mvc-best-practices-part-1.aspx#prg

+0

真棒!我更接近!在ImportModelStateFromTempData上,我可以看到它在呈现Logon.cshtml时遇到了这个问题,并且它获取了错误,但是当它呈现Login.cshtml(子部分视图)时,它正在触及else并将其删除。因此,我需要通过错误的观点仍然迷失。父母的观点基本上是在吃他们。思考? –

+0

@Tyler - 由于'ViewResult'和'PartialViewResult'都扩展了'ViewResultBase',因此简单的修改就是改变'if'语句来检查结果是否为'ViewResultBase'而不是'ViewResult'类型。但是,如果您的其他部分视图也有显示错误的区域,则可能会显示两次。另一种方法是在Logon.cshtml而不是Login.cshtml上显示两个部分的错误。 –

+0

感谢您的帮助。我最终使用了关于使用ViewResultBase的建议。我通过添加一个tempdata值和导出错误的操作名称来防止重复的错误显示。如果当前操作与tempdata中的操作匹配,则导入过滤器仅合并模型状态。我可能还会创建另一个导入/导出过滤器,并且只会使用ViewResult将错误复制到父视图。再次感谢! –

0

我认为这个问题是您正在使用的方法。

@Html.RenderAction("Login", "Account") 

将始终调用GET登录,它没有与之关联的数据。

尝试使用:

@Html.RenderPartial("Login","Account", Model.LoginModel) 

,其中型号为LogonViewModel和LoginModel是LoginViewModel。

你LogonViewModel将成为:

public class LogonViewModel 
{ 
    public LoginViewModel LoginModel { get; set; } 
} 

然后在你的AccountController,你可以在做这样的事情:

var logonModel = new LogonViewModel(); 
    logonModel.LoginModel = model; 

    return View("Logon", logonModel);