Частичные виды и проверка (обратная передача) - PullRequest
4 голосов
/ 11 апреля 2011

Название может быть не таким ясным (потому что я не мог найти лучшего), но я пытаюсь понять, когда у вас есть нормальное (в отличие от частичного) представление, обычно есть метод действия GET который просто отображает представление с новым экземпляром модели представления и методом действия POST (обычно с тем же именем), который принимает экземпляр модели представления в качестве параметра. Внутри метода действия POST вы проверяете ModelState, действительно ли вы делаете то, что должны делать, если не визуализируете представление снова с тем же экземпляром модели представления, чтобы отобразить любые ошибки.

Это действительно одна из вещей, которые мне действительно нравятся в ASP.NET MVC, но как это работает с частичными представлениями? Если я рендеринг частичного представления с экземпляром модели представления, он отображает только частичное представление с белым фоном, вне контекста всего веб-приложения. И если я отправляю обратно обычный View, передавая экземпляр модели представления, это вызывает StackOverflowException.

Вот пример:

    public ActionResult Login()
    {
        return PartialView(new LoginViewModel());
    }

    [HttpPost]
    public ActionResult Login(LoginViewModel dto)
    {
        bool flag = false;
        if (ModelState.IsValid)
        {
            if (_userService.AuthenticateUser(dto.Email, dto.Password, false)) {
                var user = _userService.GetUserByEmail(dto.Email);
                var uSession = new UserSession
                {
                    ID = user.Id,
                    Nickname = user.Nickname
                };
                SessionManager.RegisterSession(SessionKeys.User, uSession);
                flag = true;

                if(dto.RememberMe)
                {
                    _appCookies.Email = dto.Email;
                    _appCookies.Password = dto.Password;
                }
            }
        }
        if (flag)
            return RedirectToAction("Index", "Home");
        else
        {
            ViewData.Add("InvalidLogin", "The login info you provided were incorrect.");
            return View(dto); //causes a StackOverflowException
        }
    }

ОБНОВЛЕНИЕ: Вот логин:

@inherits ModelWebViewPage<Sharwe.MVC.ViewModels.LoginViewModel>

<div class="userFormHeader"><h2>Login</h2></div>
<div id="loginBox">
    @using(Html.BeginForm("Login", "User", FormMethod.Post))
    {
        @Html.ValidationSummary(true)

        <div id="loginFormFields">
            <div class="display-field">@this.TextBox(m => m.Email).Class("emailField").Attr("rel", "email").Class("autoText")</div>

            <div class="display-field">@this.TextBox(m => m.Password).Class("passwordField").Attr("rel", "password").Class("autoText")</div>

            <div>@this.CheckBox(m => m.RememberMe) <span class="smallText">remember me</span></div>
        </div>

        <div id="loginFormActions">
            <div><input type="submit" id="loginSubmit" class="okButton" name="loginSubmit" value="Ok" /></div>
            <div> @this.Html.ActionLink("forgot password", "ForgotPassword", "User", new { @class = "verySmallText" } )</div>
        </div>
    }
</div>

Так как мне это сделать? Какие-либо предложения?

ОБНОВЛЕНИЕ: (после ответа Дарина)

Вот как теперь выглядит мой метод действий при входе:

    [HttpPost]
    public ActionResult Login(LoginViewModel dto)
    {
        bool flag = false;
        if (ModelState.IsValid)
        {
            if (_userService.AuthenticateUser(dto.Email, dto.Password, false))
            {
                var user = _userService.GetUserByEmail(dto.Email);
                var uSession = new UserSession
                {
                    ID = user.Id,
                    Nickname = user.Nickname
                };
                SessionManager.RegisterSession(SessionKeys.User, uSession);
                flag = true;

                if (dto.RememberMe)
                {
                    //create the authentication ticket
                    var authTicket = new FormsAuthenticationTicket(
                        1,
                        user.Id.ToString(), //user id
                        DateTime.Now,
                        DateTime.Now.AddMinutes(20), // expiry
                        true, //true to remember
                        "", //roles 
                        "/"
                        );

                    //encrypt the ticket and add it to a cookie
                    var cookie = new HttpCookie(FormsAuthentication.FormsCookieName,
                                                FormsAuthentication.Encrypt(authTicket));
                    Response.Cookies.Add(cookie);
                }
            }
        }
        if (flag)
        {
            return Json(new { redirectTo = Url.Action("Index", "Home") });
        }
        else
        {
            ViewData.Add("InvalidLogin", "The login info you provided were incorrect.");
            return PartialView(dto);
        }
    }

1 Ответ

2 голосов
/ 11 апреля 2011

Как вы указали в разделе комментариев, AJAX - это вариант для вас, вот как вы могли бы продолжить, AJAXи изменив форму входа. плагин jquery form отлично подходит для этой работы, и я настоятельно рекомендую его.

Чтобы вы могли предоставить идентификатор для формы входа в представлении входа в систему:

@inherits ModelWebViewPage<Sharwe.MVC.ViewModels.LoginViewModel>
<div class="userFormHeader"><h2>Login</h2></div>
<div id="loginBox">
    @using(Html.BeginForm("Login", "User", null, FormMethod.Post, new { id = "loginForm" }))
    {
        ...
    }
</div>

и затем включите JavaScript, который AJAxify этой формы:

$(function() {
    ajaxifyLoginForm();
});

function ajaxifyLoginForm() {
    $('#loginForm').ajaxForm({
        success: function(html) {
            $('#loginBox').html(html);
            ajaxifyLoginForm();
        }
    });
}

Теперь осталось только вернуть частичное представление из действия контроллера Login в случае ошибки:

return PartialView(dto);

Нам также нужно разобраться с успешным случаем. Это можно сделать, вернув строку JSON:

return Json(new { redirectTo = Url.Action("Index", "Home") });

и затем адаптировать клиентский скрипт:

function ajaxifyLoginForm() {
    $('#loginForm').ajaxForm({
        success: function(data) {
            if (data.redirectTo != null && data.redirectTo != '') {
                // Everything went fine => the user is successfully 
                // authenticated let's redirect him
                window.location.href = data.redirectTo;
            } else {
                // the model state was invalid or the user entered incorrect
                // credentials => refresh the login partial in the DOM and
                // reajaxify the form:
                $('#loginBox').html(data);
                ajaxifyLoginForm();
            }
        }
    });
}
...