【问题标题】: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,但其中大多数都必须处理键数据类型的更改,例如 intGuid。在我的情况下,我不会从 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()

标签: asp.net-core asp.net-identity asp.net-identity-3


【解决方案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 MSDNUserStore&lt;TUser&gt; 的约束是 TUser : IdentityUser
    • Also according to MSDNIdentityUser : IdentityUser&lt;string, IdentityUserLogin, IdentityUserRole, IdentityUserClaim&gt;
    • 根据您的声明,User : IdentityUser&lt;string, UserClaim, UserRole, UserLogin&gt;

    长名称很容易被忽略,所以我们将IdentityUser 别名为D,将IdentityUser&lt;string, IdentityUserLogin, IdentityUserRole, IdentityUserClaim&gt; 别名为B。现在上面可以重述为:

    • TUser : DTUser 必须是 D 的一种)
    • D : BDB的一种)
    • User : B(你的User一般是B的一种,但不是D的一种,根据需要)

    【讨论】:

    • 你绝对是正确的西奥多罗斯。我试图删除长声明,一切正常。感谢您的建议。
    【解决方案3】:

    问题出在这里RoleClaim必须是IdentityRoleClaim&lt;TKey&gt;类型

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

    而不是TRoleClaim

    where TRole : IdentityRole<TKey, TUserRole, TRoleClaim>
    

    It's reported here as a bug.

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-07-13
      • 1970-01-01
      • 2022-11-17
      • 2016-09-30
      • 2016-11-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多