0

MVC3アーキテクチャでネストされたビューを設定するのに問題があります。これは私が現在持っているものです:

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

つまり、基本的には、マスターページである_Layout.cshtmlページがあります。次に、Logon.cshtmlがあります。これは、ログオンページの「マスターページ」として機能します。その下に、Login.cshtmlとForgotPassword.cshtmlの2つの部分的なビューがあります。このすべての背後に、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>

LoginビューとForgotPassword部分ビューをHtml.RenderActionでレンダリングしたことに注意してください。これらはそれぞれ実際にはフォームであり、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>
}

ご覧のとおり、これは単純な形式です。注意すべきことの1つは、ここで2つのモデルを使用しようとしていることです。ビューごとに1つ。1つは親用で、もう1つは両方の子ビュー用です(forgotpasswordにも1つあります)。とにかく、私のAccountControllerをお見せしましょう

Controllers / 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ビューをレンダリングするために戻ってください。エラー。完全を期すために、提供されたビューの2つの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; }
}
4

2 に答える 2

2

私の意見では、これを処理する最善の方法は、インデックス ページにリダイレクトすることです。しかし、あなたが言及したように、これによりエラーが失われます。

ただし、これには優れた解決策があります。モデルの状態を TempData に保存し、インデックス ページに再インポートします。[ImportModelStateFromTempData]これを非常にシームレスにするために使用できるいくつかの優れた属性を提供するリンクを次に示します。[ExportModelStateToTempData]

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

于 2012-11-09T18:12:41.377 に答える
0

問題はあなたが使用しているアプローチだと思います。

@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);
于 2012-11-09T18:47:10.233 に答える