И логин и регистрационная форма в одном представлении MVC3 Razor - PullRequest
4 голосов
/ 08 мая 2011

Моя задача - создать форму входа и регистрации в одном окне!

У меня есть вид из дома. На домашнем экране у меня есть две формы, войти и зарегистрироваться. Они отображаются с помощью @ Html.RenderPartial (частичное имя, модель). Эта форма относится к контроллеру аккаунта (действия входа и регистрации).

Позвольте мне сначала предоставить вам некоторый код ...

Модель

// Login model, that contains email and password
public class Login
{
    …
}
// Registration model that contains minimum user data, e.g. name, surname
public class Register
{
    ...
}
// Model for home view which contains models for both register and login
public class Home
{
    public Login    LoginModel    { get; set; }
    public Register RegisterModel { get; set; }
}

Просмотры : Index.cshtml

@model App.Models.Home.Home
<!-- Login Box -->
@{ Html.RenderPartial("_LoginArea", Model.LoginModel); }
<!-- Register Box -->
@{ Html.RenderPartial("_RegisterArea", Model.RegisterModel); }

_LoginArea.cshtml

@model App.Models.Account.Login
<div style="float: left; margin-right: 100px;">
    <h1>@Localization.Account.Login</h1>
    <!-- Login form -->
    <div id="loginBox">
    @using (Html.BeginForm("Login", "Account", FormMethod.Post)) 
    {    
        <div class="editor-label">
        @Html.LabelFor(m => m.Email):
        </div>
        <div class="editor-field">
        @Html.TextBoxFor(m => m.Email)
        @Html.ValidationMessageFor(m => m.Email)
        </div>
        <div class="editor-label">
        @Html.LabelFor(m => m.Password):
        </div>
        <div class="editor-field">
        @Html.PasswordFor(m => m.Password)
        @Html.ValidationMessageFor(m => m.Password)
        </div>
        <div class="editor-label">
        @Html.CheckBoxFor(m => m.RememberMe)
        @Html.LabelFor(m => m.RememberMe)
        </div>
        <p>
            <input type="submit" value="@Localization.Account.Login" />
        </p>    
    }
    </div>
</div>

_RegisterArea.cshtml

@model App.Models.Account.Register
<div style="vertical-align: bottom;">
    <h1>@Localization.Account.Register</h1>
    <div>
    @using (Html.BeginForm("Register", "Account"))
    {
        //same things like in login
    } 
    ...

Контроллеры:

HomeController

//
// GET: /Home/

public ActionResult Index(Home model)
{
    //
    // If logedin redirect to profile page
    // Else show home page view
    //

    if (Request.IsAuthenticated)
    {
        return RedirectToAction("Index", "User", new { id = HttpContext.User.Identity.Name });
    }
    else
    {
        model.LoginModel = new Login();
        model.RegisterModel = new Register();
        return View(model);
    }
}

Просто покажите действие входа из контроллера аккаунта

// 
// POST: /Account/Login

[HttpPost]
public ActionResult LogIn(Login model)
{
    if (Request.IsAuthenticated)
    {
        return RedirectToAction("Index", "User", new { id = HttpContext.User.Identity.Name });
    }
    else
    {
        if (ModelState.IsValid)
        {
            if (model.ProcessLogin())
            {
                return RedirectToAction("Index", "User", new { id = HttpContext.Session["id"] });
            }
         }
     }

     //Note: this is problem part
     // If we got this far, something failed, redisplay form
     return View("~/Views/Home/Index.cshtml", model);
}

Так что все отлично работает, НО ! Когда состояние модели недействительно, у меня есть следующее исключение

The model item passed into the dictionary is of type 'App.Models.Account.Login', but this dictionary requires a model item of type App.Models.Home.Home'.

Я могу связать эти частичные виды и действия учетной записи с моделью Home, но это не то, что мне нужно. Я планирую использовать представление _LoginArea.cshtml в других представлениях (например, в заголовке страницы представления «Пользователь», и это представление имеет другую модель) Итак, мне нужен метод действия (например, Login) для получения модели Login, а не Home или чего-либо еще. Но в этом случае я не могу вернуть модель в начальный вид. Как я могу решить эту проблему? Что является лучшим правильным способом? Извините за большое количество кода, просто хочу ясных вещей.

Ответы [ 2 ]

3 голосов
/ 08 мая 2011

В этом случае я бы порекомендовал иметь центральную страницу входа / регистрации, на которую пользователи будут перенаправлены, когда проверка не удалась . Для примера предположим, что это представление с именем SiteAuthenticate

Таким образом, в случае вашего действия LogIn(Login model), если проверка не удалась, вы всегда возвращали бы представление SiteAuthenticate, которое было бы строго типизировано, чтобы включать модели Login и Register, очень похожие на ваши Home модель.

Последним преимуществом этого подхода будет добавление свойства ReturnUrl к моделям Login и Register. Это может быть заполнено, как вы хотите, или использовать что-то вроде Request.UrlReferrer. Таким образом, вы будете знать, куда отправить пользователя обратно, когда он в конечном итоге успешно войдет / зарегистрируется.

Итак, когда все сказано и сделано, ваше действие LogIn может выглядеть примерно так:

[HttpPost]
public ActionResult LogIn(Login model)
{
    if (Request.IsAuthenticated)
    {
        return RedirectToAction(model.ReturnUrl);
    }
    else
    {
        if (ModelState.IsValid)
        {
            if (model.ProcessLogin())
            {
                return RedirectToAction(model.ReturnUrl);
            }
         }
     }

     // If we got this far, something failed. Return the generic SiteAuthenticate view
     var saModel = new SiteAuthModel { LoginModel = model };
     return View("~/Views/Account/SiteAuthenticate.cshtml", saModel);
}

Ваш SiteAuthenticate также затем отправит обратно на то же действие Login. Поскольку вы прошли первоначальный RetunrUrl, если вход в систему будет успешным, использование будет перенаправлено в исходное место назначения, как и планировалось.

Надеюсь, это поможет, дайте мне знать, если что-то неясно или не имеет смысла.

2 голосов
/ 09 мая 2011

РЕШИТЬ !!!Вместо этого используется Html.RenderAction .Вот код:

Index.cshtml

<!-- Login form -->
@{ Html.RenderAction("Login", "Account"); }

<!-- Register form -->
@{ Html.RenderAction("Register", "Account"); }

Частичные представления одинаковы ...

Действия контроллера:

//
// GET: /Account/Login

public ActionResult Login()
{
    Login model = new Login();

    if (TempData.ContainsKey("Login"))
    {
         ModelStateDictionary externalModelState = (ModelStateDictionary)TempData["Login"];
         foreach (KeyValuePair<string, ModelState> valuePair in externalModelState)
         {
             ModelState.Add(valuePair.Key, valuePair.Value);
         }
    }

    return View("_LoginHome", model);
}

// 
// POST: /Account/Login

[HttpPost]
public ActionResult Login(Login model)
{
    if (Request.IsAuthenticated)
    {
        return RedirectToAction("Index", "User", new { id = HttpContext.User.Identity.Name });
    }
    else
    {
        if (ModelState.IsValid)
        {
            if (model.ProcessLogin())
            {
                return RedirectToAction("Index", "User", new { id = HttpContext.Session["id"] });
            }
        }                
    }

    TempData.Remove("Login");
    TempData.Add("Login", ModelState);

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

То же самое для действий реестра.

Как вы можете видеть, я использую TempData для хранения состояния модели, а затем извлекаю его, когда действие начинает рендеринг.Другой вопрос, как мы можем узнать, куда мы должны вернуться, если состояние модели недействительно.Мое решение - разобрать Request.UrlReferrer , как сказал ataddeini.

Большое спасибо моему другу Данильчук Ярослав за помощь!

...