Considerations
I created a new MVC4 internet application. Out of the box, it comes with this class in the account models:
[Table("UserProfile")]
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
}
It looks like a good place to add all my other user information and to link my tables to. The fact that it's called a "Profile" seems a bit odd to me, as this appears to be the "base" user class.
I see a table in the database called webpages_Membership
, but I don't know where the model for that is. When using OpenID to create an account, it doesn't look like a record even gets inserted in there. I believe that's just for local accounts, thus "UserProfile" seems to be the only thing a user is guaranteed to have.
Anyway, the base Controller
class appears to have a Profile
property defined as a ProfileBase
but when I inspect using the debugger, it's a System.Web.Profile.DefaultProfile
, and it doesn't seem to be "filled in". i.e., IsAnonymous
is true, and UserName
is null
, even when I'm logged in.
I'm guessing this is intentional? Am I expected to override that by defining my own base controller?
I see this question and this article which talk about extending ProfileBase
, but that approach seems a bit messy to me.
Question
With all the aforementioned considerations, it seems best to me to just add all my extra properties to the UserProfile
class that's already been created for me, then add a new BaseController
class that extends Controller
, and override/new the Profile
property to return a UserProfile
instead. (1) Is this a good approach?
It took me awhile, but I eventually figured out how to get the UserProfile
object for the currently logged in user:
udb.UserProfiles.Single(p => p.UserName == User.Identity.Name);
(2) Is that the best way to get it? The UserProfile
has a UserId
property, but I can't figure out how to retrieve it. (3) How can I get the UserId for the currently logged in user?
I was thinking I could have the property lazy-load the profile so it only hits the database the first time you access that property. I read some other articles that talk about json-serializing the entire user class so it doesn't have to hit the DB every page load, but that sounds even messier, and you risk the data getting out of sync.
Implementation
Just tried this:
public class BaseController : Controller
{
private UsersContext _udb = new UsersContext();
private UserProfile _profile = null;
public new UserProfile Profile
{
get
{
if(_profile == null && User.Identity.IsAuthenticated)
{
_profile = _udb.UserProfiles.Single(p => p.UserName == User.Identity.Name);
}
return _profile;
}
}
}
Seems to work flawlessly.