4

I'm trying to find an elegant way of having login form in the master page. That means unless user logs in, login form should appear on every page. (This is very common these days)

Taking the example that comes with MVC2 Application in Visual Studio I have created this:

public class MasterViewModel
{
    public string User { get; set; } // omitted validation attributes
    public string Pass{ get; set; }
    public bool RememberMe { get; set; }
}

Every view model inherits from MasterViewModel

public class RegisterViewModel : MasterViewModel
{
    public string UserName { get; set; }
    public string Email { get; set; }
    public string Password { get; set; }
    public string ConfirmPassword { get; set; }
}

My master page renders partial view

<%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage<MyLogon.ViewModels.MasterViewModel>" %>
.....
            <div id="logindisplay">
                <% Html.RenderPartial("LogOn"); %>
            </div> 
......

Strongly-typed partial view:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<MyLogon.ViewModels.MasterViewModel>" %>
    <%
        if (Request.IsAuthenticated) {
    %>
            Welcome <b><%= Html.Encode(Page.User.Identity.Name) %></b>!
            <div>[ <%= Html.ActionLink("Change Password", "ChangePassword", "Account") %> ]</div>        
            <div>[ <%= Html.ActionLink("Log Off", "LogOff", "Account") %> ]</div>
    <%
        }
        else {
    %> 
        <%= Html.ValidationSummary(true, "Login was unsuccessful. Please correct the errors and try again.") %>

        <% using (Html.BeginForm("LogOn", "Account",FormMethod.Post)) { %>
            <div>
                <fieldset>
                    <legend>Account Information</legend>

                    <div class="editor-label">
                        <%= Html.LabelFor(m => m.User) %>
                    </div>
                    <div class="editor-field">
                        <%= Html.TextBoxFor(m => m.User) %>
                        <%= Html.ValidationMessageFor(m => m.User) %>
                    </div>

                    <div class="editor-label">
                        <%= Html.LabelFor(m => m.Pass) %>
                    </div>
                    <div class="editor-field">
                        <%= Html.PasswordFor(m => m.Pass) %>
                        <%= Html.ValidationMessageFor(m => m.Pass) %>
                    </div>

                    <div class="editor-label">
                        <%= Html.CheckBoxFor(m => m.RememberMe) %>
                        <%= Html.LabelFor(m => m.RememberMe) %>
                    </div>              
                    <p>
                        <input type="submit" value="Log On" />
                    </p>
                </fieldset>
            </div>
        <% } %>
    <%
        }
    %>

Register page:

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MyLogon.Models.RegisterViewModel>" %>
...
    <h2>Create a New Account</h2>
    <p>
        Use the form below to create a new account. 
    </p>
    <p>
        Passwords are required to be a minimum of <%= Html.Encode(ViewData["PasswordLength"]) %> characters in length.
    </p>

    <% using (Html.BeginForm("Register", "Account" ,FormMethod.Post))
       { %>
        <%= Html.ValidationSummary(true, "Account creation was unsuccessful. Please correct the errors and try again.") %>
        <div>
            <fieldset>
                <legend>Account Information</legend>

                <div class="editor-label">
                    <%= Html.LabelFor(m => m.UserName) %>
                </div>
                <div class="editor-field">
                    <%= Html.TextBoxFor(m => m.UserName) %>
                    <%= Html.ValidationMessageFor(m => m.UserName) %>
                </div>

                <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.LabelFor(m => m.ConfirmPassword) %>
                </div>
                <div class="editor-field">
                    <%= Html.PasswordFor(m => m.ConfirmPassword) %>
                    <%= Html.ValidationMessageFor(m => m.ConfirmPassword) %>
                </div>

                <p>
                    <input type="submit" value="Register" />
                </p>
            </fieldset>
        </div>
    <% } %>
</asp:Content>

Since all view models inherit from MasterViewModel LogOn partial view is always satisfied but I'm finding this solution very inelegant. Is there any other way to achieve this?

4

1 回答 1

2

照原样使用部分视图,但根据登录状态有不同的视图。使用登录表单/连接到注册页面的匿名用户返回一个视图,并为登录用户返回第二个视图。

部分视图可以有自己的模型,不需要从主视图模型继承。

继承模型可能会在以后导致问题(这使得使用html.EditForModel().DisplayForModel()棘手,因为它们也会呈现公共主视图字段)。

哦,一般来说,视图依赖于模型之外的任何东西都是不好的做法——你的测试Request.IsAuthenticated现在可能很好,但如果你想绝对正确,你应该有一个model.IsAuthenticated由操作设置的属性。也就是说,切换视图将完全避免这个问题。

编辑:最后一项改进。在这样的行上:

Welcome <b><%= Html.Encode(Page.User.Identity.Name) %></b>!

而是这样做:

Welcome <b><%: Page.User.Identity.Name %></b>!

实际上更好的是只打模型:

Welcome <b><%: model.Username %></b>!

(注意<%:不是<%=)。这种形式的标记表明内容应该是 HTML 编码的。更好的是,如果它遇到 a string,它将对其进行编码。如果它遇到一个HTMLString,它不会。所有 .Net MVC 函数都会根据需要返回字符串或 HTML 字符串,因此您可以执行以下操作:

<%: html.EditFor(x => x.fieldname) %>
<%: model.somefield %>

第一个不会被 html 编码为EditFor()返回一个HTMLString. 第二个将被编码(如果somefield是标准字符串)

这将使您的代码更整洁、更健壮。您还可以使用它来动态生成 HTML,如果您必须对其进行编码/不适当编码。例如,我们有一些辅助函数要处理,包括 CSS/JS。他们返回 HTMLStrings...

<%: Helper.IncludeCSS("SomeCSS.css") %>
于 2010-11-15T21:35:06.717 回答