1

I am building a website using ASP.NET MVC v5.2, Entity Framework v6.0 (Code First) and Identity 2.0.

I have the following code in my UserAdmin controller:

    // GET: /UserAdmin/Details/5
    public async Task<ActionResult> Details(string id)
    {
        if (id == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }

        var user = await UserManager.FindByIdAsync(id);
        return View(user);
    }

My problem is that while I can populate a user's roles with the UserManager, it is not picking up the roles associated with that user when using the FindByIdAsync method.

Here is data from the IdentityUserRole table which shows for the highlighted user assigned to two roles: enter image description here

Here is the debug info showing the same user as above but the Roles count is zero: enter image description here

Why are the roles for this user not being returned?

Edit #1

I am not using the default implementations for UserManager.

My ApplicationUser extends IdentityUser to allow me to add custom properties. My ApplicationDbContext extends IdentityDbContext.

Here's where I set up my primary keys for Identity using Fluent API:

        modelBuilder.Entity<IdentityUserLogin>().HasKey<string>(l => l.UserId);
        modelBuilder.Entity<IdentityRole>().HasKey<string>(r => r.Id);
        modelBuilder.Entity<IdentityUserRole>().HasKey(r => new { r.RoleId, r.UserId });
Dhaust
  • 5,470
  • 9
  • 54
  • 80
  • Are you using the default implementations for UserManager, UserStore etc? – Excommunicated Oct 30 '14 at 21:12
  • 1
    a) I can see that your `IdentityUserRole` has columns `ApplicationUser_Id` and `IdentityRole_Id`. They should not be there. Adjust your DbContext to remove these columns. b) You need to load roles specifically, when you load user from DbContext - similar to this: http://stackoverflow.com/a/26663667/809357 – trailmax Oct 30 '14 at 22:13
  • @Excommunicated No, my ApplicationUser extends IdentityUser with custom properties. My ApplicationDBContext also extends IdentityDbContext. I'm setting up the relationships via Fluent API. – Dhaust Oct 30 '14 at 22:26
  • @trailmax I'm not sure what part of my DbContext is causing those two extra columns to be there. I've added some code to my post to show how I'm setting up the keys with Fluent API. – Dhaust Oct 30 '14 at 23:53
  • What does `IdentityUserRole` looks like? – trailmax Oct 31 '14 at 00:02
  • @trailmax The only place I manually set anything for IdentityUserRole is in the ApplicationDbContext OnModelCreating method. modelBuilder.Entity().HasKey(r => new { r.RoleId, r.UserId }); – Dhaust Oct 31 '14 at 00:06
  • Then you'll need to have your own class that inherits from `IdentityUserRole` and specify there the only fields `RoleId` and `UserId`. But I now doubt that this is your major issue with roles not loading. – trailmax Oct 31 '14 at 00:16
  • @trailmax Should I be manually setting the foreign key between IdentiyUser and Roles? Something like this: modelBuilder.Entity().HasMany(u => u.Roles).WithOptional().HasForeignKey(r => r.UserId); I thought that wasn't necessary because that relationship is handles in the IdentityUserRole table. This is my first MVC app so please forgive me butchering any of the terminology or concepts. – Dhaust Oct 31 '14 at 00:27
  • No, I don't remember doing this. I had to specify the keys (you already have that) and override the class itself. – trailmax Oct 31 '14 at 00:38
  • If i were you i would have deleteted the fluent api code (this is what causes the multiple keys in the database) and then drop database and rebuild it from scratch. – Łukasz Trzewik Oct 31 '14 at 07:56

1 Answers1

4

As you are extending the IdentityDbContext and IdentityUser, you don't need to define your relationships for Logins, Roles and UserRoles as they are already defined in the base classes. You need to remove the lines like modelBuilder.Entity<IdentityUserRole>().HasKey(r => new { r.RoleId, r.UserId }); as they are taken care of.

As for not using the default UserManager There is a possibility here I see based on the code you have provided.

The default implementation for UserManager takes an IUserStore<TUser> as a parameter in it's constructor. If you are using (or deriving from) the UserStore<TUser> implementation in the Microsoft.AspNet.Identity.EntityFramework Library, the things like Roles, Claims and Logins are being included in the queries being made to the database. If you are creating your own class implementing IUserStore<TUser> then you will need to include the related data yourself. an example is shown below.

    public class ApplicationUser : IdentityUser
    {
        //Add your Custom Properties here..
    }

    public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
    {

        //Add your Custom Properties here..
    }


    public class ApplicationUserStore : IUserStore<ApplicationUser>
    {
        private readonly ApplicationDbContext _context;

        public ApplicationUserStore(ApplicationDbContext context)
        {
            _context = context;
        }

        public async Task<ApplicationUser> FindByIdAsync(string userName)
        {
            return await _context.Users.Include(x => x.Roles).FirstOrDefaultAsync(n => n.UserName == userName);
        }
    }
Excommunicated
  • 1,252
  • 8
  • 14
  • Cheers for the good info. Checking it out and will mark it as the answer if it sorts it out. In addition to removing the Fluent API manual key setup, I'm also testing out calling `base.OnModelCreating(modelBuilder);` in the `OnModelCreating` as per http://stackoverflow.com/a/19995982/242 – Dhaust Nov 06 '14 at 01:37