3

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.

Alexandr
  • 5,460
  • 4
  • 40
  • 70
  • 2
    Have you checked the answers for [this question](https://stackoverflow.com/q/49154250)? – Matt.G Mar 26 '19 at 14:49
  • Possible duplicate of [ASP.NET Identity's UserManager caches users?](https://stackoverflow.com/questions/49154250/asp-net-identitys-usermanager-caches-users) – Spotted Mar 26 '19 at 14:59
  • @Matt.G yes, they have set up an instance of user manager with Unity. I am using user manager out of the box instantiated for me by the framework. – Alexandr Mar 26 '19 at 14:59

1 Answers1

4

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.

Spotted
  • 4,021
  • 17
  • 33