0

This question asks about how to retrieve all users from AspNetCore Identity, in an async method:

ASP.NET Identity 2 UserManager get all users async

The non-sync method is simple:

[HttpGet]
public ActionResult<IEnumerable<UserDto>> GetAsync()
{
    var users = userManager.Users
        .ToList()
        .Select(user => user.AsDto());
    return Ok(users);
}

The obvious solution is this:

[HttpGet]
public async Task<ActionResult<IEnumerable<UserDto>>> GetAsync()
{
    var users = await userManager.Users
        .ToListAsync()
        .Select(user => user.AsDto());
    return Ok(users);
}

But this doesn't work because userManager.Users is an IQueryable<>, and that doesn't define a .ToListAsync().

The recommended answer in the question above is:

public async Task<List<User>> GetUsersAsync()
{
    using (var context = new YourContext())
    {
        return await UserManager.Users.ToListAsync();
    }
}

But that is tied to Entity Framework, and if you're using AspNetCore.Identity.MongoDbCore, you won't have any dbcontexts, and the above simply doesn't work.

One comment on the answer points out that the .ToListAsync() extension method is defined in System.Data.Entity - but if you're using MongoDb you won't be including that.

How, actually, do you access all users from UserManager<> in an async method?

Jeff Dege
  • 11,190
  • 22
  • 96
  • 165

1 Answers1

0

Basiccally, AspNetCore.Identity.MongoDbCore was just implementation wrapping around core concept of AspNetCore.Identity. And things gone just a bit difference from Sql implementation, cause they doesn't make use of unit of work concept (I know, SaveChange implement would wrap operation in transaction, but for everymethod call, the query execute immediately got this pretty similar to mongo in someway).

Then, If we need any furthur extension of those basic task, why don't just write our own implementation on top of default MongoDbCore implementation like good old days ?

// Starting with UserStore
public class ApplicationUserStore : MongoUserStore<How many generic would depend on use cases>, IApplicationUserStore
{
    protected IMongoCollection<TUser> ApplicationUsersCollection;
    public ApplicationUserStore(ApplicationDbContext context, IdentityErrorDescriber describer = null) : base(context, describer)
    {
        ApplicationUsersCollection = Context.GetCollection<TUser>();
    }

    public async Task<ICollection<ApplicationUser>> GetAllUserAsync() => // We have access to UsersCollection, implement as normal mongodb operation;
}

// Then, UserManager
public class ApplicationUserManager : UserManager<How many generic would depend on use cases>
{
    private readonly IApplicationUserStore _applicationUserStore;

    // Constructtor that could resolve our ApplicationUserStore.
    public ApplicationUserManager(IApplicationUserStore applicationUserStore,...)
    {
        _applicationUserStore = applicationUserStore;
    }

    public async Task<ICollection<ApplicationUser>> GetAllUserAsync() => _applicationUserStore.GetAllUserAsync();

// Registering things
services.AddScoped<IApplicationUserStore, ApplicationUserStore>();
services.AddScoped<ApplicationUserManager>();
}

This was just describe the idea, implementation should be vary.

Gordon Khanh Ng.
  • 1,352
  • 5
  • 12
  • The way I see it, nothing in this should depend upon Mongo, any more than it should depend upon EF. – Jeff Dege Oct 06 '21 at 05:10
  • It would be possible if `Mongodb.Driver` support `IQueryable` good enough (which I don't thing currently possible, although It does support, but there's still a big gap compare to native `Definition`). – Gordon Khanh Ng. Oct 06 '21 at 07:41