I'm working in MVC5/WebAPI using ASP.NET Identity, with a custom storage provider for my UserStore
, custom ApplicationUser
inheriting from IdentityUser
, and a pretty expansive configuration in the project (both MVC5 and WebAPI endpoints in the same project).
I've been working on the user management/settings controller (ManageController
), following the same principles the template projects use; however, with the additional fields I have in my ApplicationUser
, it is getting to the point that my view model is starting to be a duplicate of the ApplicationUser
class. I wanted someone to take a look at some of my code and let me know if they think the way I'm setting things up currently is appropriate, or if I am cluttering a view model with fields.
ManageViewModels.cs
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNet.Identity;
using Microsoft.Owin.Security;
using System.Security.Claims;
namespace Disco.Models
{
public class IndexViewModel
{
public string Email { get; set; }
public bool HasPassword { get; set; }
public IList<UserLoginInfo> Logins { get; set; }
public string PhoneNumber { get; set; }
public bool TwoFactor { get; set; }
public bool BrowserRemembered { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Picture { get; set; }
public string Handle { get; set;}
}
public class ManageLoginsViewModel
{
public IList<UserLoginInfo> CurrentLogins { get; set; }
public IList<AuthenticationDescription> OtherLogins { get; set; }
}
public class FactorViewModel
{
public string Purpose { get; set; }
}
public class SetPasswordViewModel
{
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "New password")]
public string NewPassword { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm new password")]
[Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
}
public class ChangePasswordViewModel
{
[Required]
[DataType(DataType.Password)]
[Display(Name = "Current password")]
public string OldPassword { get; set; }
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "New password")]
public string NewPassword { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm new password")]
[Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
}
public class AddPhoneNumberViewModel
{
[Required]
[Phone]
[Display(Name = "Phone Number")]
public string Number { get; set; }
}
public class VerifyPhoneNumberViewModel
{
[Required]
[Display(Name = "Code")]
public string Code { get; set; }
[Required]
[Phone]
[Display(Name = "Phone Number")]
public string PhoneNumber { get; set; }
}
public class ConfigureTwoFactorViewModel
{
public string SelectedProvider { get; set; }
public ICollection<System.Web.Mvc.SelectListItem> Providers { get; set; }
}
}
ApplicationUser.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNet.Identity;
using System.Security.Claims;
using Newtonsoft.Json;
namespace Schloss.AspNet.Identity.Neo4j
{
public class ApplicationUser : IdentityUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTimeOffset DateOfBirth { get; set; }
// @ handle / username
public string Handle { get; set; }
public string Picture { get; set; }
public char Gender { get; set; }
public string DeviceId { get; set; } // Most recently used mobile phone ID (iPhone, iPad, Android, etc)
// Address
public string City { get; set; }
public string State { get; set; }
public string ZIPCode { get; set; }
public string County { get; set; }
public string Country { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string Address3 { get; set; }
// SignalR
public HashSet<string> ConnectionIds { get; set; } // SignalR connections set (for handling multiple live sessions, propagation of push notifications)
//public static string Labels { get { return "User"; } }
// Helper Properties
[JsonIgnore]
public String FullName
{
get { return (FirstName + " " + LastName).Trim(); } // helper property to format user's full name
}
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager, string authenticationType)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, authenticationType);
// Add custom user claims here
return userIdentity;
}
}
}
ManageController.cs (just the Index view)
//
// GET: /Manage/Index
public async Task<ActionResult> Index(ManageMessageId? message)
{
ViewBag.StatusMessage =
message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed."
: message == ManageMessageId.SetPasswordSuccess ? "Your password has been set."
: message == ManageMessageId.SetTwoFactorSuccess ? "Your two-factor authentication provider has been set."
: message == ManageMessageId.Error ? "An error has occurred."
: message == ManageMessageId.AddPhoneSuccess ? "Your phone number was added."
: message == ManageMessageId.RemovePhoneSuccess ? "Your phone number was removed."
: "";
var userId = User.Identity.GetUserId();
var user = await UserManager.FindByIdAsync(userId);
var model = new IndexViewModel
{
Email = await UserManager.GetEmailAsync(userId),
HasPassword = await UserManager.HasPasswordAsync(userId),
PhoneNumber = await UserManager.GetPhoneNumberAsync(userId),
TwoFactor = await UserManager.GetTwoFactorEnabledAsync(userId),
Logins = await UserManager.GetLoginsAsync(userId),
BrowserRemembered = await AuthenticationManager.TwoFactorBrowserRememberedAsync(userId),
FirstName = user.FirstName,
LastName = user.LastName,
Picture = user.Picture,
Handle = user.Handle
};
return View(model);
}