Background
I have a website written in ASP.NET Core v2.1.1.
I have a custom identity user class:
public class FooIdentityUser : IdentityUser<string>, IIdentityModel
{
[MaxLength(50)]
public string FirstName { get; set; }
[MaxLength(50)]
public string LastName { get; set; }
public string FullName => $"{FirstName} {LastName}";
public bool FooBool { get; set; }
}
and a custom identity role class:
public class FooIdentityRole : IdentityRole<string>
{
}
Which I then reference in the dbcontext:
public class FooIdentityDbContext : IdentityDbContext<FooIdentityUser,FooIdentityRole,string>
{
public FooIdentityDbContext(DbContextOptions<FooIdentityDbContext> options)
: base(options)
{
}
}
Requirement
My overall requirement is that I want to give system admin users the ability to view and eventually manage user data from within the admin area of the website.
Specifically:
- I want to provide a list of users that are in a foo role
- And / or I want to list all users that have FooBool set to true
- And / or I want to query on email address, first name & last name
- And / or carry out a sort
Question
Does anyone have any links to web pages where this has been done before or can you respond on how I can implement this feature? I have attempted a couple of approaches below.
Approaches / Research
From what I can see there are two approaches to doing this:
Approach 1
Because I want to list users specifically for a user role based in a view, I can see that user manager provides a method for this:
_userManager.GetUsersInRoleAsync(fooRoleName)
The issue I have with this is it returns an IList so whilst it will return all users with this role, if I want to query on FooBool and / or FirstName, LastName or Email Address, it will need to cycle through the list to filter these out which would be inefficient if there are 10s of thousands or 100s of thousands of users?
Ideally, this would return an IQueryable so it wouldn't hit the database until my where and order by had been applied but I can't find a way of doing this?
Approach 2
The other way may be to query the context directly through my generic repository.
public class GenericIdentityRepository<TModel> : IIdentityRepository<TModel> where TModel : class, IIdentityModel
{
private readonly ILogger _logger;
public FooIdentityDbContext Context { get; set; }
private readonly DbSet<TModel> _dbSet;
public GenericIdentityRepository(FooIdentityDbContext dbContext, ILogger<GenericIdentityRepository<TModel>> logger)
{
Context = dbContext;
_logger = logger;
_dbSet = Context.Set<TModel>();
}
public IQueryable<TModel> GetAll()
{
_logger.LogDebug("GetAll " + typeof(TModel));
IQueryable<TModel> query = _dbSet;
return query;
}
public IQueryable<TModel> GetAllNoTracking()
{
_logger.LogDebug("GetAllNotTracking " + typeof(TModel));
IQueryable<TModel> query = GetAll().AsNoTracking();
return query;
}
}
I was looking to see if I could do something by creating custom classes for userrole and then using linq to give me an IQueryable?
public class FooIdentityUserRole : IdentityUserRole<string>
{
public virtual FooIdentityUser User { get; set; }
public virtual FooIdentityRole Role { get; set; }
}
And then somehow query the data to return an IQueryable but I'm struggling to produce the correct linq I need to do this.