My MVVM and MVC User models have usually been a hierarchy of different classes starting with the simplest name/password and adding more properties with each inherited subclass.
(Side Note: I've noticed a tendency to add more properties to different versions of subclasses can get out of hand, mucking up a membership provider, when mixed with Roles, when what is really called for is a Profile provider for all those descriptive properties. See Decorate Pattern and MS ProfileProvider.)
This time a client requirement surprised me by making even username/password optional, which I've never done. As a matter of fact, most of my user hierarchy was built to support the base class of required properties using MVC DataAnnotation Required Attributes. So
I rewrote it as one base User with no requireds, and then various subclasses more like ViewModels. Also I Interfaced the User and changed all my Membership and Repository arguments to the interface. Now this pattern seems much more flexible, simple, and easily extensible. Don't know why I didn't see this before.
public interface IUserModel
{
int Id { get; set; }
string EmailAddress { get; set; }
string Password { get; set; }
bool Active { get; set; }
string FirstName { get; set; }
string LastName { get; set; }
string PhoneNumber { get; set; }
bool GetsEmail { get; set; }
IEnumerable<RoleModel> Roles { get; set; }
}
[Serializable]
public class UserModel : IUserModel
{
[Key]
public int Id { get; set; }
[Display(Name = "Email Address")]
[StringLength(255)]
[MyLibrary.Web.Mvc3.Attributes.EmailAddress]
public virtual string EmailAddress { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Password")]
public virtual string Password { get; set; }
[Display(Name = "Active")]
public bool Active { get; set; }
[Display(Name = "First name")]
[StringLength(50)]
public virtual string FirstName { get; set; }
[Display(Name = "Last name")]
[StringLength(50)]
public string LastName { get; set; }
[StringLength(255)]
[Display(Name = "Phone Number")]
public string PhoneNumber { get; set; }
[Display(Name = "Gets Emails?")]
public bool GetsEmail { get; set; }
[Display(Name = "Roles")]
public IEnumerable<RoleModel> Roles { get; set; }
}
public class LogOnModel : UserModel
{
[Required]
[Display(Name = "Email Address")]
[StringLength(255)]
[MyLibrary.Web.Mvc3.Attributes.EmailAddress]
public override string EmailAddress { get; set; }
[Required]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public override string Password { get; set; }
}
public class RegisterModel : LogOnModel
{
[Required(ErrorMessage = "Please enter a first name")]
public override string FirstName { get; set; }
[DataType(DataType.Password)]
[Compare("Password")]
[Display(Name = "Confirm Password")]
public string PasswordConfirm { get; set; }
}
public class ChangePasswordModel : UserModel
{
[Required]
[DataType(DataType.Password)]
[Display(Name = "Old Password")]
public string OldPassword { get; set; }
[Required]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public override string Password { get; set; }
[DataType(DataType.Password)]
[Compare("Password")]
[Display(Name = "Confirm Password")]
public string PasswordConfirm { get; set; }
}
public class FoundPasswordModel : UserModel
{
[Required]
public override string EmailAddress { get; set; }
[Required]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public override string Password { get; set; }
[DataType(DataType.Password)]
[Compare("Password")]
[Display(Name = "Confirm Password")]
public string PasswordConfirm { get; set; }
}
public class ValidatedUserModel : UserModel
{
[Required] [StringLength(255)]
[MyLibrary.Web.Mvc3.Attributes.EmailAddress] public override string EmailAddress { get; set; }
[Required(ErrorMessage = "Please enter a first name")]
public override string FirstName { get; set; }
public ValidatedUserModel() { }
public ValidatedUserModel(IUserModel user)
{
Active = user.Active;
EmailAddress = user.EmailAddress;
FirstName = user.FirstName;
GetsEmail = user.GetsEmail;
Id = user.Id;
LastName = user.LastName;
PhoneNumber = user.PhoneNumber;
Roles = user.Roles;
}
}