1

I want to include theme support for the bootswatch themes in my MVC 5 app.

I want the users theme to be saved and loaded when they log in.

I have extended my user class to include the theme and can successfully set and save a theme on the edit user page.

public class User : IdentityUser
{       
public string BootstrapTheme {get;set;}
}

In the BootstrapTheme property I'll save the href attribute for the bootstrap css link. eg "~/Content/bootstrap.flatly.min.css"

The plan is to set the theme in the layout page.

<link href="~/Content/bootstrap.spacelab.min.css" rel="stylesheet" />

How can I do this without querying the database on every page load?

Being able to do something like <link href="@User.BootstrapTheme" rel="stylesheet" /> would be ideal.

Here is a link on how to save it for one page using localstorage http://wdtz.org/bootswatch-theme-selector.html

tereško
  • 58,060
  • 25
  • 98
  • 150
woggles
  • 7,444
  • 12
  • 70
  • 130

1 Answers1

8

You should store theme name/url as a claim on the user, not as part of the User class:

await userManager.AddClaimAsync(user.Id, new Claim("MyApp:ThemeUrl", "~/Content/bootstrap.flatly.min.css"));

When user is logged in, this claim is added to the cookie and you can access it through extension method:

public static String GetThemeUrl(this ClaimsPrincipal principal)
{
    var themeClaim = principal.Claims.FirstOrDefault(c => c.Type == "MyApp:ThemeUrl");
    if (themeClaim != null)
    {
        return themeClaim.Value;
    }
    // return default theme url if no claim is set
    return "path/to/default/theme";
}

and in your view you would access theme url like this:

<link href="@ClaimsPrincipal.Current.GetThemeUrl()" rel="stylesheet" />

Claims on principal are available in the cookie, so no extra DB hits required.

As an alternative you can persist user BootstrapTheme as you already have done, but when user is logging in, add this theme as a claim to the identity:

public async Task SignInAsync(IAuthenticationManager authenticationManager, ApplicationUser applicationUser, bool isPersistent)
{
    authenticationManager.SignOut(
        DefaultAuthenticationTypes.ExternalCookie,
        DefaultAuthenticationTypes.ApplicationCookie);

    var identity = await this.CreateIdentityAsync(applicationUser, DefaultAuthenticationTypes.ApplicationCookie);

    identity.AddClaim(new Claim("MyApp:ThemeUrl", applicationUser.BootstrapTheme));

    authenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
}

And then access the claim in the view via above-mentioned extension method. I've blogged recently about similar scenario - you can have a look there for a bit more insight how claims work.

trailmax
  • 34,305
  • 22
  • 140
  • 234
  • thanks, I'll have a look into claims based auth. I've avoided it until now because of our SharePoint division moaning about it for 2 years :) – woggles Aug 19 '14 at 20:35
  • I've recently converted 2 mvc projects into AspNet Identity and started using claims - the code is so much better and easier to maintain! And performance is increased as well - less calls to DB! – trailmax Aug 19 '14 at 20:52
  • Worked Like a charm. – Unbreakable Aug 22 '17 at 06:11
  • One thing to note is we need to add "@using System.Security.Claims" in the Razor view. (ASP.Net MVC 5 project) – Unbreakable Aug 22 '17 at 06:11