首页 > 解决方案 > IDesignTimeDbContextFactory[TContext] 违反

问题描述

我目前正在使用这个快速入门示例,并且正在努力让它发挥作用。由于遇到无穷无尽的异常,我已经放弃了先开发数据库,​​而是希望从实体生成表,这不是我让事情正常工作的首选方式。

我这样做似乎不太幸运......

我目前反对这个例外:

PM> dotnet ef 数据库更新 CustomerDbContext System.ArgumentException: GenericArguments[0], 'IdentityServerWithAspIdAndEF.Migrations.CustomerDbContext', on 'Microsoft.EntityFrameworkCore.Design.IDesignTimeDbContextFactory1[TContext]' violates the constraint of type 'TContext'. ---> System.TypeLoadException: GenericArguments[0], 'IdentityServerWithAspIdAndEF.Migrations.CustomerDbContext', on 'Microsoft.EntityFrameworkCore.Design.IDesignTimeDbContextFactory1[TContext]'违反了类型参数'TContext'的约束。在 System.RuntimeTypeHandle.Instantiate(RuntimeTypeHandle 句柄, IntPtr* pInst, Int32 numGenericArgs, ObjectHandleOnStack type) 在 System.RuntimeTypeHandle.Instantiate(Type[] inst) 在 System.RuntimeType.MakeGenericType(Type[] 实例化) --- 内部结束异常堆栈跟踪---在 System.RuntimeType.ValidateGenericArguments(MemberInfo 定义,RuntimeType [] genericArguments,异常 e)在 System.RuntimeType.MakeGenericType(Type [] 实例化)在 Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.FindContextFactory(类型contextType) 在 Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations 的 Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.FindContextTypes()。

对我来说,这与“错误,出现错误”一样具有描述性……我采用了原始快速入门并进行了以下修改。

Startup.ConfigureServices就是现在:

public void ConfigureServices(IServiceCollection services)
{
    string connectionString = Configuration.GetConnectionString("DefaultConnection");
    var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;

    services.AddDbContext<CustomerDbContext>(options =>
        options.UseSqlServer(connectionString)
    );

    services.AddIdentity<User, Role>()
        .AddUserStore<CustomerUserStore>()
        .AddUserManager<CustomerManager>()
        .AddRoleStore<CustomerRoleStore>()
        .AddRoleManager<RoleManager>()
        .AddSignInManager<CustomerSignInManager>()
        .AddDefaultTokenProviders();

    services.AddMvc();

    services.Configure<IISOptions>(iis =>
    {
        iis.AuthenticationDisplayName = "Windows";
        iis.AutomaticAuthentication = false;
    });

    var builder = services.AddIdentityServer(options =>
        {
            options.Events.RaiseErrorEvents = true;
            options.Events.RaiseInformationEvents = true;
            options.Events.RaiseFailureEvents = true;
            options.Events.RaiseSuccessEvents = true;
        })
        .AddAspNetIdentity<User>()
        // this adds the config data from DB (clients, resources)
        .AddConfigurationStore(options =>
        {
            options.ConfigureDbContext = b =>
                b.UseSqlServer(connectionString,
                    sql => sql.MigrationsAssembly(migrationsAssembly));
        })
        // this adds the operational data from DB (codes, tokens, consents)
        .AddOperationalStore(options =>
        {
            options.ConfigureDbContext = b =>
                b.UseSqlServer(connectionString,
                    sql => sql.MigrationsAssembly(migrationsAssembly));

            // this enables automatic token cleanup. this is optional.
            options.EnableTokenCleanup = true;
            // options.TokenCleanupInterval = 15; // frequency in seconds to cleanup stale grants. 15 is useful during debugging
        });

    if (Environment.IsDevelopment())
    {
        builder.AddDeveloperSigningCredential();
    }
    else
    {
        throw new Exception("need to configure key material");
    }

    services.AddAuthentication();
}

ApplicationDbContext已重命名为CustomerDbContextOnModelCreating现在是:

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

    ModelBuilder.Entity<User>(E =>
    {
        E.ToTable("Users");
    });

    ModelBuilder.Entity<Role>(E =>
    {
        E.ToTable("Roles");
    });

    ModelBuilder.Entity<RoleClaim>(E =>
    {
        E.ToTable("RoleClaims");
    });

    ModelBuilder.Entity<UserClaim>(E =>
    {
        E.ToTable("UserClaims");
    });

    ModelBuilder.Entity<UserRole>(E =>
    {
        E.ToTable("UserRoles");
    });

    // "Microsoft.AspNetCore.Identity.IdentityUserLogin<string>"
    ModelBuilder.Entity<Login>(E =>
    {
        E.Property(P => P.LoginId)
            .IsRequired()
            .HasColumnName("LoginId")
            .ValueGeneratedOnAdd();

        E.HasIndex(P => P.LoginProvider)
            .HasName("IX_Logins_LoginProvider");

        E.HasIndex(P => P.ProviderKey)
            .HasName("IX_Logins_ProviderKey");

        E.HasIndex(P => P.UserId)
            .HasName("IX_Logins_AccountId");

        E.ToTable("Logins");
    });

    // "Microsoft.AspNetCore.Identity.IdentityUserToken<string>"
    ModelBuilder.Entity<Token>(E =>
    {
        E.Property(P => P.TokenId)
            .IsRequired()
            .HasColumnName("TokenId")
            .ValueGeneratedOnAdd();

        E.ToTable("Tokens");
    });
}

最后,我只是将一堆东西放在一起让模型工作;所以ApplicationUser文件现在包含:

public class User : IdentityUser<int>
{
}

public class Role : IdentityRole<int>
{
}

public class RoleClaim : IdentityRoleClaim<int>
{
}

public class UserClaim : IdentityUserClaim<int>
{
}

public class Login : IdentityUserLogin<int>
{
    public int LoginId { get; set; }
}

public class UserRole : IdentityUserRole<int>
{
}

public class Token : IdentityUserToken<int>
{
    public int TokenId { get; set; }
}
public class CustomerManager : UserManager<User>
{
    /// <summary>
    /// Constructs a new instance of <see cref="T:Microsoft.AspNetCore.Identity.UserManager`1" />.
    /// </summary>
    /// <param name="Store">The persistence store the manager will operate over.</param>
    /// <param name="OptionsAccessor">The accessor used to access the <see cref="T:Microsoft.AspNetCore.Identity.IdentityOptions" />.</param>
    /// <param name="PasswordHasher">The password hashing implementation to use when saving passwords.</param>
    /// <param name="UserValidators">A collection of <see cref="T:Microsoft.AspNetCore.Identity.IUserValidator`1" /> to validate users against.</param>
    /// <param name="PasswordValidators">A collection of <see cref="T:Microsoft.AspNetCore.Identity.IPasswordValidator`1" /> to validate passwords against.</param>
    /// <param name="KeyNormaliser">The <see cref="T:Microsoft.AspNetCore.Identity.ILookupNormalizer" /> to use when generating index keys for users.</param>
    /// <param name="Errors">The <see cref="T:Microsoft.AspNetCore.Identity.IdentityErrorDescriber" /> used to provider error messages.</param>
    /// <param name="Services">The <see cref="T:System.IServiceProvider" /> used to resolve services.</param>
    /// <param name="Logger">The logger used to log messages, warnings and errors.</param>
    public CustomerManager(
        IUserStore<User> Store,
        IOptions<IdentityOptions> OptionsAccessor,
        IPasswordHasher<User> PasswordHasher,
        IEnumerable<IUserValidator<User>> UserValidators,
        IEnumerable<IPasswordValidator<User>> PasswordValidators,
        ILookupNormalizer KeyNormaliser,
        IdentityErrorDescriber Errors,
        IServiceProvider Services,
        ILogger<UserManager<User>> Logger
    ) : base(
        Store,
        OptionsAccessor,
        PasswordHasher,
        UserValidators,
        PasswordValidators,
        KeyNormaliser,
        Errors,
        Services,
        Logger
    )
    { }
}

public class RoleManager : RoleManager<Role>
{
    /// <summary>
    /// Constructs a new instance of <see cref="T:Microsoft.AspNetCore.Identity.RoleManager`1" />.
    /// </summary>
    /// <param name="Store">The persistence store the manager will operate over.</param>
    /// <param name="RoleValidators">A collection of validators for roles.</param>
    /// <param name="KeyNormalizer">The normalizer to use when normalizing role names to keys.</param>
    /// <param name="Errors">The <see cref="T:Microsoft.AspNetCore.Identity.IdentityErrorDescriber" /> used to provider error messages.</param>
    /// <param name="Logger">The logger used to log messages, warnings and errors.</param>
    public RoleManager(
        IRoleStore<Role> Store,
        IEnumerable<IRoleValidator<Role>> RoleValidators,
        ILookupNormalizer KeyNormalizer,
        IdentityErrorDescriber Errors,
        ILogger<RoleManager<Role>> Logger
    ) : base(
        Store,
        RoleValidators,
        KeyNormalizer,
        Errors,
        Logger
    )
    { }
}

public class CustomerSignInManager : SignInManager<User>
{
    /// <summary>
    /// Creates a new instance of <see cref="T:Microsoft.AspNetCore.Identity.SignInManager`1" />.
    /// </summary>
    /// <param name="UserManager">An instance of <see cref="P:Microsoft.AspNetCore.Identity.SignInManager`1.UserManager" /> used to retrieve users from and persist users.</param>
    /// <param name="ContextAccessor">The accessor used to access the <see cref="T:Microsoft.AspNetCore.Http.HttpContext" />.</param>
    /// <param name="ClaimsFactory">The factory to use to create claims principals for a user.</param>
    /// <param name="OptionsAccessor">The accessor used to access the <see cref="T:Microsoft.AspNetCore.Identity.IdentityOptions" />.</param>
    /// <param name="Logger">The logger used to log messages, warnings and errors.</param>
    /// <param name="Schemes">The logger used to log messages, warnings and errors.</param>
    public CustomerSignInManager(
        UserManager<User> UserManager,
        IHttpContextAccessor ContextAccessor,
        IUserClaimsPrincipalFactory<User> ClaimsFactory,
        IOptions<IdentityOptions> OptionsAccessor,
        ILogger<SignInManager<User>> Logger,
        IAuthenticationSchemeProvider Schemes
    ) : base(
        UserManager,
        ContextAccessor,
        ClaimsFactory,
        OptionsAccessor,
        Logger,
        Schemes
    )
    { }
}

public class CustomerUserStore : UserStore<User, Role, CustomerDbContext, int, UserClaim, UserRole, Login, Token, RoleClaim>
{
    public CustomerUserStore(CustomerDbContext Context) : base(Context)
    {

    }
}

public class CustomerRoleStore : RoleStore<Role, CustomerDbContext, int, UserRole, RoleClaim>
{
    /// <summary>
    /// Constructs a new instance of <see cref="T:Microsoft.AspNetCore.Identity.EntityFrameworkCore.RoleStore`5" />.
    /// </summary>
    /// <param name="context">The <see cref="T:Microsoft.EntityFrameworkCore.DbContext" />.</param>
    /// <param name="describer">The <see cref="T:Microsoft.AspNetCore.Identity.IdentityErrorDescriber" />.</param>
    public CustomerRoleStore(
        CustomerDbContext context,
        IdentityErrorDescriber describer = null
    ) : base(
        context,
        describer
    )
    { }

    /// <summary>Creates a entity representing a role claim.</summary>
    /// <param name="role">The associated role.</param>
    /// <param name="claim">The associated claim.</param>
    /// <returns>The role claim entity.</returns>
    protected override RoleClaim CreateRoleClaim(Role role, Claim claim)
    {
        return new RoleClaim
        {
            RoleId = role.Id,
            ClaimType = claim.Type,
            ClaimValue = claim.Value
        };
    }
}

我已经导航到该src/IdentityServerWithAspIdAndEF文件夹​​,将“启动项目”设置为IdentityServerWithAspIdAndEF,然后运行以下命令来尝试生成表:

PM> Add-Migration CustomerDbContext -Context CustomerDbContext 接着 PM> dotnet ef database update CustomerDbContext

第一个生成Migrations文件夹和预期的 *.cs 文件;第二个产生了在这篇文章顶部看到的错误。

任何人都可以就可能产生此错误的原因提出建议吗?

标签: c#entity-framework-coreidentityserver4

解决方案


最常见的解决方法是删除迁移文件夹中具有相同名称的所有迁移,但是如果这不起作用,我建议删除所有迁移并删除已创建的数据库。

然后您应该能够运行Add-Migration CustomerDbContext -Context CustomerDbContext并且dotnet ef database update没有错误。


推荐阅读