【问题标题】:IDesignTimeDbContextFactory[TContext] violates theIDesignTimeDbContextFactory[TContext] 违反
【发布时间】:2020-08-02 23:15:51
【问题描述】:

我目前正在与this quickstart example 合作,并且正在努力让它发挥作用。由于遇到无穷无尽的异常,我已经放弃了先开发数据库,​​而是希望从实体中生成表,这不是我首选的工作方式。

我似乎不太走运……

我目前正在处理这个异常:

PM> dotnet ef 数据库更新 CustomerDbContext System.ArgumentException: GenericArguments[0], 'IdentityServerWithAspIdAndEF.Migrations.CustomerDbContext', on 'Microsoft.EntityFrameworkCore.Design.IDesignTimeDbContextFactory1[TContext]' violates the constraint of type 'TContext'. ---&gt; System.TypeLoadException: GenericArguments[0], 'IdentityServerWithAspIdAndEF.Migrations.CustomerDbContext', on 'Microsoft.EntityFrameworkCore.Design.IDesignTimeDbContextFactory1[TContext]' 违反了类型参数 'TContext' 的约束。 在 System.RuntimeTypeHandle.Instantiate(RuntimeTypeHandle 句柄,IntPtr* pInst,Int32 numGenericArgs,ObjectHandleOnStack 类型) 在 System.RuntimeTypeHandle.Instantiate(类型 [] 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.FindContextTypes() 在 Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.FindContextType(字符串名称) 在 Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(字符串 contextType) 在 Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.UpdateDatabase(字符串 targetMigration,字符串 contextType) 在 Microsoft.EntityFrameworkCore.Design.OperationExecutor.UpdateDatabase.c__DisplayClass0_1.<.ctor>b__0() 在 Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(操作动作) GenericArguments[0], 'IdentityServerWithAspIdAndEF.Migrations.CustomerDbContext', on 'Microsoft.EntityFrameworkCore.Design.IDesignTimeDbContextFactory`1[TContext]' 违反了'TContext' 类型的约束。

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

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&gt; Add-Migration CustomerDbContext -Context CustomerDbContext 接着 PM&gt; dotnet ef database update CustomerDbContext

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

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

【问题讨论】:

  • 不确定这是否是个问题,但您将PMC commands(first) 与dotnet ef commands(second) 混合在一起。如果第一个成功了,值得一试PM&gt;Update-Database
  • @IvanStoev:不幸的是,这些命令的任何组合都会产生相同的异常,我开始将它们混合起来看看是否可以使用一种组合。

标签: c# entity-framework-core identityserver4


【解决方案1】:

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

然后您应该能够运行Add-Migration CustomerDbContext -Context CustomerDbContextdotnet ef database update 而不会出错。

【讨论】:

  • 看起来当您在一个位置启动项目然后将其移动到另一个位置然后您想要更新您的数据库时,您需要删除您的迁移文件。谢谢丹尼尔的回答!
【解决方案2】:

您应该能够在脚本中重命名迁移后运行它。

Add-Migration **CustomerDbContext** -Context CustomerDbContext

重命名迁移后它对我有用。

【讨论】:

    【解决方案3】:

    由于在创建 DBContext 和初始迁移后我尝试更改我的 DbContext 名称并更新数据库,我遇到了同样的错误。我回滚了 DbContext 中的名称,一切都开始按预期工作。

    【讨论】:

      【解决方案4】:

      我遇到了同样的问题。 删除所有迁移和“迁移”文件夹后,它工作正常。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-06-13
        • 2018-10-04
        • 2018-09-25
        • 1970-01-01
        • 2014-07-31
        • 2013-06-15
        • 2020-05-15
        相关资源
        最近更新 更多