【问题标题】:Nested Views in MVC 3 issuesMVC 3 问题中的嵌套视图
【发布时间】:2012-11-10 02:47:10
【问题描述】:

在我的 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>

请注意,我已经使用 Html.RenderAction 渲染了 Login 和 ForgotPassword 部分视图。我这样做是因为它们中的每一个实际上都是表单,它们需要发布到 AccountController。接下来,让我向您展示我的 Login.cshtml 文件:

Views/Account/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>
}

如您所见,这只是一个简单的表格。需要注意的一件事是,我在这里尝试使用两个模型。每个视图一个。一个用于父视图,一个用于两个子视图(forgotpassword 也有一个)。不管怎样,让我给你看看我的 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] Login(...) 上,我正在检查用户的凭据是否正确。如果是这样,一切正常,但问题出在错误上。如果我使用return View("Logon");,我想我会陷入无限循环,如果我使用return View(model),我会得到Login.cshtml 的部分视图,如果我使用return RedirectToAction("Index", "Home");,我会正确返回到我的登录视图,但是我添加的错误没有出现(当我return View(model); 时它们确实出现了。我在这里做错了什么?我认为我的设置是有道理的,但我不知道如何让它正常工作。我会就像返回以呈现带有错误的 Logon.cshtml 视图。为了完整起见,这是我提供的视图的两个 ViewModel:

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; }
}

【问题讨论】:

    标签: c# asp.net-mvc-3


    【解决方案1】:

    在我看来,处理此问题的最佳方法是重定向回索引页面。但是正如您所提到的,这会导致您的错误丢失。

    对此有一个很好的解决方案 - 将模型状态保存在 TempData 中,然后在索引页面上重新导入。这是一个链接,它提供了几个不错的属性,您可以使用它来实现无缝连接:[ImportModelStateFromTempData][ExportModelStateToTempData]

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

    【讨论】:

    • 太棒了!我更近了!在 ImportModelStateFromTempData 上,我可以看到它在渲染 Logon.cshtml 时遇到了这个错误,但是当它渲染 Login.cshtml(子部分视图)时,它遇到了 else 并且正在删除它。因此,我需要解决错误的观点仍然迷失了。父视图基本上是吃掉它们。想法?
    • @Tyler - 简单的解决方法是更改​​if 语句以检查结果是否为ViewResultBase 类型而不是ViewResult,因为ViewResultPartialViewResult 都扩展@987654329 @。但是,如果您的其他部分视图也有显示错误的区域,则它们可能会显示两次。另一种方法是只在 Logon.cshtml 而不是 Login.cshtml 上显示两个部分的错误。
    • 感谢您的帮助。我最终使用了您关于使用 ViewResultBase 的建议。我通过添加一个带有在导出时引发错误的操作名称的临时数据值来防止重复错误显示。如果当前操作与临时数据中的操作匹配,则导入过滤器只会合并模型状态。我可能还会创建另一个过滤器来导入/导出,并且只使用 ViewResult 将错误冒泡到父视图。再次感谢!
    【解决方案2】:

    我认为问题在于您使用的方法。

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

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

    尝试使用:

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

    其中 Model 是 LogonViewModel,LoginModel 是 LoginViewModel。

    您的 LogonViewModel 将变为:

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

    然后在您的 AccountController 中,您可以执行以下操作:

        var logonModel = new LogonViewModel();
        logonModel.LoginModel = model;
    
        return View("Logon", logonModel);
    

    【讨论】:

      猜你喜欢
      • 2021-11-22
      • 1970-01-01
      • 2017-04-13
      • 2013-08-04
      • 2017-04-03
      • 2014-06-30
      • 2013-01-08
      • 2011-11-22
      • 1970-01-01
      相关资源
      最近更新 更多