ASP.NET Core Identity: the base class (IdentityUser, IdentityRole, IdentityUserRole e.t.c.) Implementation

asp.net asp.net-core asp.net-identity entity-framework entity-framework-core

Question

Context:

public class ApplicationDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, Guid, UserClaim, UserRole, 
            UserLogin, RoleClaim, UserToken>
        {
            public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
                        : base(options)
            {
            }


            protected override void OnModelCreating(ModelBuilder builder)
            {
                base.OnModelCreating(builder);
            }
        }

Entity classes of Identity:

    public class ApplicationUser : IdentityUser<Guid, UserClaim, UserRole, UserLogin>
    {
    }

    public class ApplicationRole : IdentityRole<Guid, UserRole, RoleClaim>
    {
    }

    public class UserRole : IdentityUserRole<Guid>
    {
    }

    public class RoleClaim : IdentityRoleClaim<Guid>
    {
    }

    public class UserClaim : IdentityUserClaim<Guid>
    {
    }

    public class UserLogin : IdentityUserLogin<Guid>
    {
    }

    public class UserToken : IdentityUserToken<Guid>
    {
    }

Class Startup.cs:

    services.AddDbContext<ApplicationDbContext>(options =>                                 options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

    services.AddIdentity<ApplicationUser, ApplicationRole>()
             .AddEntityFrameworkStores<ApplicationDbContext, Guid>()
             .AddDefaultTokenProviders();

When the application starts, it throws the following exception:

GenericArguments[0], 'del.Models.ApplicationUser', on 'Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore`4[TUser,TRole,TContext,TKey]' violates the constraint of type 'TUser'.

Exception img How to solve this problem? Classes "UserRole, RoleClaim" is needed.

1
0
8/22/2016 7:25:47 PM

Popular Answer

I had the same issue just today. I am heavily extending the Identity system to support things that I need in my application. One of the things I noticed is that since the IdentityUser has A LOT of different derived classes, it is not always as simple as overriding just "IdentityUser<>".

Having said that, the exception is getting thrown in the ExtensionMethod "AddEntityFrameworkStores()". The reason for this is that that extension method also uses a private helper method that dynamically creates a generic type:

userStoreType = typeof(UserStore<,,,>).MakeGenericType(userType, roleType, contextType, keyType);

UserStore<> also has a lot of different generic signatures. I created my own derived UserStore (ApplicationUserStore) so that I could create my own ApplicationUserRole. In doing that, the creation of the generic type would no longer work. I had to create my own version of the extension method that was:

userStoreType = typeof(ApplicationUserStore<,,,>).MakeGenericType(userType, roleType, contextType, keyType);

Now, this my not be your "exact" issue, but I'm 99% sure this is it. You may need to create your own derived UserStore using the following signature:

public class ApplicationUserStore : UserStore<ApplicationUser, ApplicationRole, ApplicationDbContext, Guid>
{
  ...
}

Then create a new Extensions method class that duplicates the original but changes the UserStore creation.

public static class IdentityEntityFrameworkBuilderExtensions2
{        
    public static IdentityBuilder AddEntityFrameworkStores2<TContext>(this IdentityBuilder builder)
        where TContext : DbContext
    {
        builder.Services.TryAdd(GetDefaultServices(builder.UserType, builder.RoleType, typeof(TContext)));
        return builder;
    }

    public static IdentityBuilder AddEntityFrameworkStores2<TContext, TKey>(this IdentityBuilder builder)
        where TContext : DbContext
        where TKey : IEquatable<TKey>
    {
        builder.Services.TryAdd(GetDefaultServices(builder.UserType, builder.RoleType, typeof(TContext), typeof(TKey)));
        return builder;
    }

    private static IServiceCollection GetDefaultServices(Type userType, Type roleType, Type contextType, Type keyType = null)
    {
        Type userStoreType;
        Type roleStoreType;
        keyType = keyType ?? typeof(string);
        userStoreType = typeof(ApplicationUserStore<,,,>).MakeGenericType(userType, roleType, contextType, keyType);
        roleStoreType = typeof(ApplicationRoleStore<,,>).MakeGenericType(roleType, contextType, keyType);

        var services = new ServiceCollection();
        services.AddScoped(
            typeof(IUserStore<>).MakeGenericType(userType),
            userStoreType);
        services.AddScoped(
            typeof(IRoleStore<>).MakeGenericType(roleType),
            roleStoreType);
        return services;
    }
} 

Hopefully this helps.

2
9/8/2016 2:17:06 AM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow