I am using ASP.NET Core & Identity 3.
When I log in I read the current select user's UI template and in my _Layout.cshml
file I load the css
based off this template.
The user can change his theme and I store it in a session variable via the controller
public IActionResult ChangeTheme(int id, string returnUrl)
{
HttpContext.Session.SetInt32("Template", (id));
return Redirect(returnUrl);
}
Instead of querying the database with every cshtml
load I put the Template in a Session variable and in my Layout.cshtml
I render a different css depending on the template
switch (template)
{
case (int)TemplateEnum.Template2:
<text>
<link rel="stylesheet" href="~/css/template1.css" />
</text>
break;
case (int)TemplateEnum.Template2:
<text>
<link rel="stylesheet" href="~/css/template2.css" />
</text>
break;
{
I'm wondering what happens if the session expires.
Taking into account I access the value in my _Layout.cshtml
is there anyway to catch it if it becomes null and immediately load it from the db before a new page is rendered.
Since I use Identity 3, is Claims maybe a better option? I haven't used it before. What would the code be for my example above
Another option that is better for my scenario?
Instead of querying the database with every cshtml load I put the Template in a Session variable and in my Layout.cshtml I render a different css depending on the template
If hitting the database is your only concern and you have abstracted your repository (or user store, if you store it on the identity type), you can use the decorator pattern to implement local caching.
public interface IUserRepository
{
string GetUserTheme(int userId);
void SetUserTheme(int userId, string theme);
}
public class CachedUserRepository : IUserRepository
{
private readonly IMemoryCache cache;
private readonly IUserRepository userRepository;
// Cache Expire duration
private static TimeSpan CacheDuration = TimeSpan.FromMinutes(5);
public CachedUserRepository(IUserRepository userRepository, IMemoryCache memoryCache)
{
if (userRepository == null)
throw new ArgumentNullException(nameof(userRepository));
if (memoryCache == null)
throw new ArgumentNullException(nameof(memoryCache));
this.userRepository = userRepository;
this.cache = memoryCache;
}
public string GetUserTheme(int userId)
{
string theme;
// adding a prefix to make the key unique
if (cache.TryGetValue($"usertheme-{userId}", out theme))
{
// found in cache
return theme;
};
// fetch from database
theme = userRepository.GetUserTheme(userId);
// put it into the cache, expires in 5 minutes
cache.Set($"usertheme-{userId}", theme, new MemoryCacheEntryOptions { AbsoluteExpirationRelativeToNow = CacheDuration });
return theme;
}
public void SetUserTheme(int userId, string theme)
{
// persist it
userRepository.SetUserTheme(userId, theme);
// put it into the cache, expires in 5 minutes
cache.Set($"usertheme-{userId}", theme, new MemoryCacheEntryOptions { AbsoluteExpirationRelativeToNow = CacheDuration });
}
}
The catch is, there is no built-in support for decorators in the default ASP.NET Core DI system. You'd have to use a 3rd party IoC container (Autofac, StructureMap etc.).
You could of course register it like this
services.AddScoped<IUserRepository>(container => {
return new CachedUserRepository(container.GetService<UserRepository>(), container.GetServices<IMemoryCache>());
});
but that's a bit cumbersome. Otherwise store it in a long-lived cookie, it has the advantage that the theme will still be active when the user is not logged in and you can set the cookie, when the user logs in.