登录和注册都在一个视图MVC3 Razor上形成

时间:2011-05-08 13:24:50

标签: c# asp.net-mvc asp.net-mvc-3 razor partial-views

我的任务是在一个视图上创建登录和注册表单!

我有家的看法。在主视图中,我有两种形式,登录和注册。它们由@ 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视图(例如在'User'视图的页眉中,该视图有另一个模型) 所以,我需要动作方法(例如Login)来检索Login模型,而不是Home或其他任何东西。但在这种情况下,我无法将模型返回到Home视图。 我该如何解决这个问题?什么是最好的方法? 很抱歉有很多代码,只想要清楚的事情。

2 个答案:

答案 0 :(得分:3)

在这种情况下,我建议建立一个中央登录/注册页面,用户将在验证失败时重定向到。出于示例的目的,假设这是一个名为SiteAuthenticate

的视图

因此,对于您的LogIn(Login model)操作,如果验证失败,您将始终返回SiteAuthenticate视图,该视图将被强类型化以包含LoginRegister模型,与您的Home模型非常相似。

使此方法有效的最后一个方法是向ReturnUrlLogin模型添加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,如果登录成功,则该用途将按计划重定向到其原始目的地。

希望有所帮助,如果有任何不清楚或没有意义,请告诉我。

答案 1 :(得分:2)

解决!!!使用 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说的那样。

非常感谢我的朋友 Danylchuk Yaroslav 为他提供帮助!