0
votes

I have a user model that contains things like login name, name, permissions, contact info, etc.

I want to display the user's name in the menu bar of my _Layout page so it's displayed across every page. I can display the logged in user like this in my _Layout page...

@User.Identity.Name.Replace(@"MYDOMAIN\", "")

But I want to pull the users real name from the model, and get their permissions to manage what they can and can't see on the company Intranet site.

The problem is, if I try to set the page model in the _Layout page, the site blows up because the @RenderBody in the _Layout loads other pages that reference their own models.

Maybe I'm looking at this wrong, but how else would you maintain the user name and permissions across your site without having each page hit the database every time you went to a new page?

Another way to look at it... Suppose your menu is data driven, and the menu exists in the _Layout page. How do you do that?

Thanks.

1

1 Answers

1
votes

First, there is no way to do this without hitting the database everytime (at least a recommended way) since you're getting user data and permissions which is subject to change.

Second, you can do an @inject in your layout and grab the user data via the ClaimsPrincipal User so you could do it like this: @inject UserManager<TheUser> userManager.

then you can do this: var user=await userManager.FindByNameAsync(User.Identity.Name) and now you populate your tags with user data.

Something like this:

_Layout.cshtml

@inject UserManager<TheUser> userManager
@{
   var user=await userManager.FindByNameAsync(User.Identity.Name)
} 

<div>
  @user.FullName
</div>

Another approach is to create a custom “claims principle” factory. Somthing like this:

public class MyUserClaimsPrincipalFactory : UserClaimsPrincipalFactory<ApplicationUser> 
{     
    public MyUserClaimsPrincipalFactory(
        UserManager<ApplicationUser> userManager,
        IOptions<IdentityOptions> optionsAccessor)
            : base(userManager, optionsAccessor)     
    {
    }
      
    protected override async Task<ClaimsIdentity>GenerateClaimsAsync(ApplicationUser user)
    {
         var identity = await base.GenerateClaimsAsync(user);
         identity.AddClaim(new Claim("FullName", user.FullName));         
         return identity;     
    } 
}

then you add it to your ConfigureServices:

services.AddIdentity<ApplicationUser, IdentityRole>()
        .AddEntityFrameworkStores<ApplicationDbContext>()
        .AddClaimsPrincipalFactory<MyUserClaimsPrincipalFactory>(); 

and now you can access it like this

User.FindFirst("FullName").Value

Also the ClaimsPrincipal User has a User.IsInRole to check for user roles.

Suppose your menu is data driven, and the menu exists in the _Layout page. How do you do that?

Usually for just data you can cache it in the servers memory so you can minimize the number of database requests (you purge the cache when "data" is modified and do a re cache) but i advise against it since your dealing with user data.