Search code examples
c#entity-framework-coreasp.net-core-mvcasp.net-core-identity

How do I read from the dbo.AspNetUsers table?


I want to retrieve data from the Identity-table dbo.AspNetUsers, but I haven't figured out how to query it.

This is my db-context:

public class ProjectsDbContext : IdentityDbContext<IdentityUser>
{
    public ProjectsDbContext(DbContextOptions<ProjectsDbContext> options) : base(options) { }

    public DbSet<Project> Projects { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        if (modelBuilder == null)
        {
            throw new NullReferenceException();
        }

        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<Project>()
            .HasMany(c => c.ChildProjects)
            .WithOne(p => p.ParentProject)
            .HasForeignKey(p => p.ParentProjectId);
    }
}

This is my User-class:

public class User : IdentityUser
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

This is the query I have, which doesn't work:

List<User> projectOwners = await db.Users.ToListAsync();

The error message I get is:

Cannot implicitly convert type 'System.Collections.Generic.List<Microsoft.AspNetCore.Identity.IdentityUser>' to 'System.Collections.Generic.List<Projects.Models.User>'

If I replace List<User> with var in the query, the error goes away, but the collection I get does not contain any of the properties from my own User-class.

How do I access the AspNetUsers, including my own extra properties defined in User?


Solution

  • Assumig you're setting your project up more or less according to standard boilerplate, I believe you can cast override type of your identity user like so:

    Startup.cs

     public void ConfigureServices(IServiceCollection services)
            {
                // pretty standard initialisation so far
                services.AddDbContext<ProjectsDbContext>(options =>
                    options.UseSqlServer(
                        Configuration.GetConnectionString("DefaultConnection")));
                services.AddDefaultIdentity<User>(options => options.SignIn.RequireConfirmedAccount = false) // this is the key - put your custom User Identity here
                    .AddEntityFrameworkStores<ProjectsDbContext>();
            }
    

    ProjectsDbContext.cs

    public class User : IdentityUser
        {
            public string FirstName { get; set; }
            public string LastName { get; set; }
        }
        public class ProjectsDbContext: IdentityDbContext<User> // this is your custom User type
        {
            public ProjectsDbContext(DbContextOptions<ProjectsDbContext> options)
                : base(options)
            {
            }
        }
    

    then, since you are changing the data model, you will need to migrate the schema:

    PM> Add-Migration change_IdentityUser
    PM> Update-Database
    

    you will notice the migration adds your custom fields to the table:

    public partial class change_IdentityUser : Migration
        {
            protected override void Up(MigrationBuilder migrationBuilder)
            {
                migrationBuilder.AddColumn<string>(
                    name: "FirstName",
                    table: "AspNetUsers",
                    nullable: true);
    
                migrationBuilder.AddColumn<string>(
                    name: "LastName",
                    table: "AspNetUsers",
                    nullable: true);
            } 
    .......
    

    and finally, all references to SignInManager/UserManager and other helpers will need to be updated with new generic type parameter:

    _LoginPartial.cshtml

    @inject SignInManager<User> SignInManager
    @inject UserManager<User> UserManager