为啥这违反了类型参数“TUser”的约束?
Posted
技术标签:
【中文标题】为啥这违反了类型参数“TUser”的约束?【英文标题】:Why this violates the constraint of type parameter 'TUser'?为什么这违反了类型参数“TUser”的约束? 【发布时间】:2017-01-25 16:43:35 【问题描述】:我正在尝试使用以下实体自定义 asp.net 身份实体:
public class User : IdentityUser<string, UserClaim, UserRole, UserLogin>
public class UserClaim : IdentityUserClaim<string>
public class UserLogin : IdentityUserLogin<string>
public class UserRole : IdentityUserRole<string>
public class UserToken : IdentityUserToken<string>
public class Role : IdentityRole<string, UserRole, RoleClaim>
public class RoleClaim : IdentityRoleClaim<string>
然后我创建了一个如下所示的 DbContext 类
public class AppDbContext : IdentityDbContext<User, Role, string, UserClaim, UserRole, UserLogin, RoleClaim, UserToken>
然后用
配置这些services
.AddIdentity<User, Role>()
.AddEntityFrameworkStores<AppDbContext>()
.AddDefaultTokenProviders();
但我也尝试过
.AddEntityFrameworkStores<AppDbContext, string>()
我在互联网上阅读了许多博客文章,例如 this,但其中大多数都必须处理键数据类型的更改,例如 int
或 Guid
。在我的情况下,我不会从 string
更改默认键数据类型。
我在所有这些情况下编译都可以,但是运行时会抛出错误
System.TypeLoadException GenericArguments[0],'MyIdentity.Entities.User', on 'Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore`8[TUser,TRole,TContext,TKey,TUserClaim,TUserRole,TUserLogin,TUserToken]' 违反类型参数'TUser'的约束。
在 System.RuntimeTypeHandle.Instantiate(RuntimeTypeHandle 句柄, IntPtr* pInst,int numGenericArgs,ObjectHandleOnStack 类型)在 System.RuntimeTypeHandle.Instantiate(Type[] inst) 在 System.RuntimeType.MakeGenericType(Type[] 实例化)
如果我添加一个自定义的UserStore
类,如this post 中所述
public class UserStore : UserStore<User, Role, AppDbContext, string, UserClaim, UserRole, UserLogin, UserToken>
出现编译错误提示
CS0311 类型“MyIdentity.Entities.Role”不能用作类型 泛型类型或方法“UserStore”中的参数“TRole”。没有隐式引用转换 'MyIdentity.Entities.Role' 到 'Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole>'
我做错了什么?
【问题讨论】:
你的User
类有默认构造函数吗?
@TheodorosChatzigiannakis:是的。我刚刚检查过了。 public User() : base()
【参考方案1】:
我遇到了这个问题,我发现了这个:"When you are customizing ASP.NET Core Identity, you should not use AddEntityFrameworkStores anymore." 你应该实现你的:
public class ApplicationRoleManager: RoleManager<Role>
public class ApplicationRoleStore : RoleStore<Role, ApplicationDbContext, int, UserRole, RoleClaim>
public class ApplicationSignInManager : SignInManager<User>
public class ApplicationUserManager : UserManager<User>
public class ApplicationUserStore : UserStore<User, Role, ApplicationDbContext, int, UserClaim, UserRole, UserLogin, UserToken, RoleClaim>
然后将内置服务重定向到您的自定义服务(Startup.cs):
services.AddScoped<UserStore<User, Role, ApplicationDbContext, int, UserClaim, UserRole, UserLogin, UserToken, RoleClaim>, ApplicationUserStore> ();
services.AddScoped<UserManager<User>, ApplicationUserManager>();
services.AddScoped<RoleManager<Role>, ApplicationRoleManager>();
services.AddScoped<SignInManager<User>, ApplicationSignInManager>();
services.AddScoped<RoleStore<Role, ApplicationDbContext, int, UserRole, RoleClaim>, ApplicationRoleStore>();
services.AddScoped<IEmailSender, AuthMessageSender>();
services.AddScoped<ISmsSender, AuthMessageSender>();
然后介绍您的自定义服务:
services.AddIdentity<User, Role>(identityOptions =>
// ...
).AddUserStore<ApplicationUserStore>()
.AddUserManager<ApplicationUserManager>()
.AddRoleStore<ApplicationRoleStore>()
.AddRoleManager<ApplicationRoleManager>()
.AddSignInManager<ApplicationSignInManager>()
// You **cannot** use .AddEntityFrameworkStores() when you customize everything
//.AddEntityFrameworkStores<ApplicationDbContext, int>()
.AddDefaultTokenProviders();
【讨论】:
【参考方案2】: According to MSDN,UserStore<TUser>
的约束是 TUser : IdentityUser
。
Also according to MSDN,IdentityUser : IdentityUser<string, IdentityUserLogin, IdentityUserRole, IdentityUserClaim>
。
根据您的声明,User : IdentityUser<string, UserClaim, UserRole, UserLogin>
。
长名称很容易被忽略,所以我们将IdentityUser
别名为D
,将IdentityUser<string, IdentityUserLogin, IdentityUserRole, IdentityUserClaim>
别名为B
。现在上面可以重述为:
TUser : D
(TUser
必须是 D
的一种)
D : B
(D
是B
的一种)
User : B
(你的User
一般是B
的一种,但不是D
的一种,根据需要)
【讨论】:
你绝对是正确的西奥多罗斯。我试图删除长声明,一切正常。感谢您的建议。【参考方案3】:问题出在这里RoleClaim
必须是IdentityRoleClaim<TKey>
类型
where TRole : IdentityRole<TKey, TUserRole, IdentityRoleClaim<TKey>>
而不是TRoleClaim
where TRole : IdentityRole<TKey, TUserRole, TRoleClaim>
It's reported here as a bug.
【讨论】:
以上是关于为啥这违反了类型参数“TUser”的约束?的主要内容,如果未能解决你的问题,请参考以下文章
GenericArguments[0], 'EntityGenericBase`1[TModel]' 违反了类型参数 'TModel' 的约束
类型参数“System.Net.Http.Headers.MediaTypeHeaderValue”违反类型参数“T”的约束
.NET 告诉我 TypeLoadException:违反类型参数“T”的约束,而我的代码显然没有违反它
为啥将 lambda 传递给受约束的类型模板参数会导致“不完整类型”编译器错误?