Identity: ASP.NET identity configuration exception and that breaks dotnet.exe run process

Created on 20 May 2016  路  13Comments  路  Source: aspnet/Identity

I am moving a project from ASP.NET Core RC1 to ASP.NET Core RC2 and I have the entities:

public class User : IdentityUser<Int32> { }

public class Role : IdentityRole<Int32> { }

On startup ConfigureServices I have the following as I had in RC1:

  services.AddIdentity<User, Role>()
      .AddEntityFrameworkStores<Context>()
      .AddDefaultTokenProviders();

It builds fine but when I run the project I get an exception and dotnet.exe shuts down:

Unhandled Exception: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.ArgumentException: GenericArguments[0], "WebApp.Entities.User", on "Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore "3[TUser,TRole,TContext]" violates the constraint of type "TUser". ---> System.TypeLoadException: GenericArguments[0], "WebApp.Entities.User", on "Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore "4[TUser,TRole,TContext,TKey]" violates the constraint of type parameter "TUser". at System.RuntimeTypeHandle.Instantiate(RuntimeTypeHandle handle, IntPtr* pInst, Int32 numGenericArgs, ObjectHandleOnStack type) at System.RuntimeTypeHandle.Instantiate(Type[] inst) at System.RuntimeType.MakeGenericType(Type[] instantiation) --- End of inner exception stack trace --- at System.RuntimeType.ValidateGenericArguments(MemberInfo definition, RuntimeType[] genericArguments, Exception e) at System.RuntimeType.MakeGenericType(Type[] instantiation) at Microsoft.Extensions.DependencyInjection.IdentityEntityFrameworkBuilderExtensions.GetDefaultServices(Type userType, Type roleType, Type contextType, Type keyType) at Microsoft.Extensions.DependencyInjection.IdentityEntityFrameworkBuilderExtensions.AddEntityFrameworkStores[TContext](IdentityBuilder builder) at WebApp.Startup.ConfigureServices(IServiceCollection services) --- End of inner exception stack trace --- at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor) at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments) at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) at Microsoft.AspNetCore.Hosting.Startup.ConfigureServicesBuilder.Invoke(Object instance, IServiceCollection exportServices) at Microsoft.AspNetCore.Hosting.Internal.WebHost.EnsureApplicationServices() at Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication() at Microsoft.AspNetCore.Hosting.WebHostBuilder.Build() at WebApp.Program.Main(String[] args)

Am I missing something?

Most helpful comment

Yeah you need to specify the TKey when you change it from string, so AddEntityFrameworkStores<Context, int>

All 13 comments

Yeah you need to specify the TKey when you change it from string, so AddEntityFrameworkStores<Context, int>

Thanks Haok

Feel free to reopen if this doesn't fix the issue

Yes, I tried just now and it worked. Just a site question: should a Window saying an error on dotnet.exe occurred and asking me if I want to close it or debug dotnet.exe? That is what happens when I don't set:

.AddEntityFrameworkStores<Context, Int32>()

Maybe dotnet.exe shoudl catch such kind of exception and displays then on console.

When using the 1.0.0-rc3-21101 nightly build, I am getting this same error even when using string as the TKey generic argument of IdentityUser, but only in cases where my ApplicationUser class explicitly extends IdentityUser<TKey, TUserClaim, TUserRole, TUserLogin> rather than IdentityUser<TKey>.

In order words, everything works fine when my ApplicationUser class is defined as follows:

public class ApplicationUser : IdentityUser<string> { ... }

but when the ApplicationUser class is defined like this:

public class ApplicationUser : IdentityUser<string, IdentityUserClaim<string>, IdentityUserRole<string>, IdentityUserLogin<string>> { ... }

the following error occurs at runtime only (but not at compilation):

GenericArguments[0], 'MyWeb.Models.ApplicationUser', on 'Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore`4[TUser,TRole,TContext,TKey]' violates the constraint of type 'TUser'.
at System.RuntimeType.ValidateGenericArguments(MemberInfo definition, RuntimeType[] genericArguments, Exception e)
at System.RuntimeType.MakeGenericType(Type[] instantiation)
at Microsoft.Extensions.DependencyInjection.IdentityEntityFrameworkBuilderExtensions.GetDefaultServices(Type userType, Type roleType, Type contextType, Type keyType)
at Microsoft.Extensions.DependencyInjection.IdentityEntityFrameworkBuilderExtensions.AddEntityFrameworkStores<TContext, TKey>(IdentityBuilder builder)
at MyWeb.Startup.ConfigureServices(IServiceCollection services)

Originally, I was using a Guid type for the key and providing my own implementations for each of the Identity role, claim and login classes, but I rolled everything back to just use all of the standard implementations as shown above to make sure that there wasn't something in my code that was causing the issue, but it made no difference.

My Startup.cs contains the following:

        services.AddIdentity<ApplicationUser, IdentityRole<string>>()
                .AddEntityFrameworkStores<ApplicationDbContext, string>()
                .AddDefaultTokenProviders();

Based on the stack trace, and looking through the code, it seems that Microsoft.Extensions.DependencyInjection.IdentityEntityFrameworkBuilderExtensions.AddEntityFrameworkStores<TContext, TKey>() is then invoking GetDefaultServices(), whose implementation attempts to instantiate a new UserStore<TUser, TRole, TContext, TKey>, rather than a new UserStore<TUser, TRole, TContext, TKey, TUserClaim, TUserRole, TUserLogin, TUserToken>. The version of the UserStore with only four generic arguments assumes that TUser will be an instance of IdentityUser<TKey>, not IdentityUser<TKey, TUserClaim, TUserRole, TUserLogin>, and it seems that perhaps this is causing the issue.

I tried to create my own implementation ofUserStore<TUser, TRole, TContext, TKey, TUserClaim, TUserRole, TUserLogin, TUserToken> called MyUserStore and modified the Startus.cs as follows:

        services.AddIdentity<ApplicationUser, IdentityRole<string>>()
                .AddEntityFrameworkStores<ApplicationDbContext, string>()
                .AddUserStore<MyUserStore>()
                .AddDefaultTokenProviders();

However, that also made no difference, as it looks like AddEntityFrameworkStores() attempts to load up the default implementation before it tries to replace it with my implementation.

My ultimate goal is to be able to create my own implementation of the various Identity classes to support a custom multi-tenant configuration, but this error is preventing me from making any progress on that front. Any light you could shed would be greatly appreciated. I do have an example zipped up, but I was not able to attach it here for some reason.

There currently isn't any sugar for AddEntityFrameworkStores for plugging in the more complicated derived IdenttyUser generics today, basically you need to mimic what that method currently does, just passing in the correct types.

Thanks for the quick response and the clarification. Do you happen to know if adding the syntactic sugar to support this sort of configuration is on the roadmap for some future release?

Not currently as the amount of generics required was a bit overwhelming in this situation.

Hi! Is here the progress in this question?

basically you need to mimic what that method currently does, just passing in the correct types.

I am attempting this and have a strange issue. Trying to recreate AddEntityFrameworkStores I have:

``` C#
public static IdentityBuilder CCIRTSAddEntityFrameworkStores(this IdentityBuilder builder) where TContext : DbContext
{
var userType = typeof(IdentityUser);
var roleType = typeof(IdentityRole);
var userStoreType = typeof(UserStore);
var roleStoreType = typeof(RoleStore);

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

    return builder;
    }
I am getting this error message:

> The type 'CCIRTS.Models.ApplicationRole' cannot be used as type parameter 'TRole' in the generic type or method 'UserStore<TUser, TRole, TContext, TKey, TUserClaim, TUserRole, TUserLogin, TUserToken>'. There is no implicit reference conversion from 'CCIRTS.Models.ApplicationRole' to 'Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole<string, CCIRTS.Models.ApplicationUserRole, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim<string>>'.
> Framework 4.5.2
> "

My ApplicationRole is:

``` C#
public class ApplicationRole : IdentityRole<String, ApplicationUserRole, ApplicationRoleClaim>
    {
        public ApplicationRole() : base() { }

        [MaxLength(128)]
        public override String Id { get; set; }
        public virtual string Description { get; set; }
        public virtual ICollection<ApplicationRoleToUserGroup> ApplicationRoleUserGroups { get; set; }
    }

My ApplicationUserRole is:

``` C#
public class ApplicationUserRole : IdentityUserRole
{
public ApplicationUserRole() : base() { }

    [MaxLength(128)]
    public override String RoleId { get; set; }

    [MaxLength(128)]
    public override String UserId { get; set; }

}
My ApplicationRoleClaim is:

``` C#
    public class ApplicationRoleClaim : IdentityRoleClaim<String>
    {
        public ApplicationRoleClaim() : base() { }
        [MaxLength(128)]
        public override String RoleId { get; set; }

    }

FYI, This is all just to get the ID to 128 character because my many to many relationship key was exceeding 900 bytes and not allowing migrations to work.

C# builder.Entity<ApplicationRoleToUserGroup>().HasKey(a => new { a.ApplicationRoleID, a.UserGroupID });

Looking more I found this:

C# public abstract class UserStore<TUser, TRole, TContext, TKey, TUserClaim, TUserRole, TUserLogin, TUserToken> : IUserLoginStore<TUser>, IUserStore<TUser>, IDisposable, IUserRoleStore<TUser>, IUserClaimStore<TUser>, IUserPasswordStore<TUser>, IUserSecurityStampStore<TUser>, IUserEmailStore<TUser>, IUserLockoutStore<TUser>, IUserPhoneNumberStore<TUser>, IQueryableUserStore<TUser>, IUserTwoFactorStore<TUser>, IUserAuthenticationTokenStore<TUser> where TUser : IdentityUser<TKey, TUserClaim, TUserRole, TUserLogin> where TRole : IdentityRole<TKey, TUserRole, IdentityRoleClaim<TKey>> where TContext : DbContext where TKey : IEquatable<TKey> where TUserClaim : IdentityUserClaim<TKey> where TUserRole : IdentityUserRole<TKey> where TUserLogin : IdentityUserLogin<TKey> where TUserToken : IdentityUserToken<TKey>

It looks like "where TRole" must have a IdentityRoleClam, not a TRoleClaim. How do I get around this?

public abstract class UserStore<TUser, TRole, TContext, TKey, TUserClaim, TUserRole, TUserLogin, TUserToken> : IUserLoginStore<TUser>, IUserStore<TUser>, IDisposable, IUserRoleStore<TUser>, IUserClaimStore<TUser>, IUserPasswordStore<TUser>, IUserSecurityStampStore<TUser>, IUserEmailStore<TUser>, IUserLockoutStore<TUser>, IUserPhoneNumberStore<TUser>, IQueryableUserStore<TUser>, IUserTwoFactorStore<TUser>, IUserAuthenticationTokenStore<TUser>
        where TUser : IdentityUser<TKey, TUserClaim, TUserRole, TUserLogin>
        where TRole : IdentityRole<TKey, TUserRole, IdentityRoleClaim<TKey>>
        where TContext : DbContext
        where TKey : IEquatable<TKey>
        where TUserClaim : IdentityUserClaim<TKey>
        where TUserRole : IdentityUserRole<TKey>
        where TUserLogin : IdentityUserLogin<TKey>
        where TUserToken : IdentityUserToken<TKey>

where TRole : IdentityRole<TKey, TUserRole, IdentityRoleClaim<TKey>>

This is a bug? Shouldn't it be TRoleClaim ?

where TRole : IdentityRole<TKey, TUserRole, TRoleClaim >

Was this page helpful?
0 / 5 - 0 ratings

Related issues

anester picture anester  路  9Comments

panchengtao picture panchengtao  路  7Comments

trailmax picture trailmax  路  6Comments

pwen090 picture pwen090  路  6Comments

PaulRReynolds picture PaulRReynolds  路  4Comments