I have an application that uses Microsoft.AspNetCore.Identity.UserManager to manage users. I use core 2.2. UserManager is injected by built-in dependency injection in my services (not by me). like this:
public MyService(UserManager<IdentityUser> userManager)
{
_userManager = userManager;
}
When I try to get a user by Id (FindByIdAsync) for the first time I see a request to db in a console. Next requests with the same Id I do not see any request to db, but the application works and got user.
In Startup.cs I do not have a configuration for userManager. I just use the extension method:
public void ConfigureServices(IServiceCollection services)
{
services
.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("MyConnectionString"));
services
.AddIdentity<IdentityUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
services.AddMvc();
var configService = new ConfigurationService(Configuration);
services
.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryApiResources(configService.GetApiResources())
.AddInMemoryClients(configService.GetClients())
.AddTestUsers(configService.GetUsers());
}
Question: Maybe there is a way how to configure this caching feature in UserManager? Point me out where to get information about how long this cache leaves.
I digged through the Identity source code on Github and ended in UserStore
:
public override Task<TUser> FindByIdAsync(string userId, CancellationToken cancellationToken = default(CancellationToken))
{
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed();
var id = ConvertIdFromString(userId);
return UsersSet.FindAsync(new object[] { id }, cancellationToken);
}
UsersSet
beeing of type DbSet<TUser>
, Identity has no way to manage caching directly but relies on EF internals.
Digging into EF source code, I ended in DbContext
:
object IDbSetCache.GetOrAddSet(IDbSetSource source, Type type)
{
CheckDisposed();
if (_sets == null)
{
_sets = new Dictionary<Type, object>();
}
if (!_sets.TryGetValue(type, out var set))
{
set = source.Create(this, type);
_sets[type] = set;
}
return set;
}
and it looks like that there is a caching mechanism backed by a plain and simple Dictionary
.
However, as Matt G. pointed in his comment, the solution to manage caching lies a level above your service: it is related to how you manage your dependency scope when injecting the UserManager
.