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?