简体   繁体   中英

IdentityServer4 database migration issue

I'm building identityserver4 using .net core 3.1. I'm using database migration to build the database. The issue I'm having is the seeding method. My seeding method is as follows:

private void ClientSeed(ModelBuilder builder)
        {
            builder.Entity<ApiResource>()
               .HasData(
                   new ApiResource
                   {
                       Name = "PatientPortalAPI",
                       DisplayName = "Patient Portal API",

                       ApiSecrets =
                       {
                           new Secret("secret".Sha256())
                       },

                       Scopes =
                       {
                           new Scope()
                           {
                                 Name = StandardScopes.OfflineAccess,
                                 DisplayName = StandardScopes.OfflineAccess,
                                 Description = null,
                                 Required = false,
                                 Emphasize = false,
                                 ShowInDiscoveryDocument = true,
                           },
                           new Scope()
                           {
                                 Name = StandardScopes.OpenId,
                                 DisplayName = StandardScopes.OpenId,
                                 Description = null,
                                 Required = false,
                                 Emphasize = false,
                                 ShowInDiscoveryDocument = true,
                           }
                       }
                   }
               );

            builder.Entity<IdentityResource>().HasData(
                    new IdentityResource()
                    {
                        Enabled = true,
                        Name = "openid",
                        DisplayName = "Your user identifier",
                        Description = null,
                        Required = true,
                        Emphasize = false,
                        ShowInDiscoveryDocument = true,
                    },
                    new IdentityResource()
                    {
                        Enabled = true,
                        Name = "profile",
                        DisplayName = "User profile",
                        Description = "Your user profile information (first name, last name, etc.)",
                        Required = false,
                        Emphasize = true,
                        ShowInDiscoveryDocument = true,
                    });

            builder.Entity<Client>()
                .HasData(
                    new Client
                    {
                        ClientId = "t8agr5xKt4$3",
                        AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,

                        ClientSecrets =
                        {
                            new Secret("secret".Sha256())
                        },

                        AllowedScopes =
                        {
                            StandardScopes.OpenId,
                            StandardScopes.Profile,
                            StandardScopes.Email,
                            StandardScopes.Address,
                            "api1",
                            StandardScopes.OfflineAccess
                        },

                        AllowOfflineAccess = true,
                        RefreshTokenUsage = TokenUsage.ReUse,
                        RefreshTokenExpiration = TokenExpiration.Sliding,
                    });
        }

The error I'm getting when I add migration is this:

System.InvalidOperationException: No suitable constructor found for entity type 'Claim'. The following constructors had parameters that could not be bound to properties of the entity type: cannot bind 'reader' in 'Claim(BinaryReader reader)'; cannot bind 'reader', 'subject' in 'Claim(BinaryReader reader, ClaimsIdentity subject)'; cannot bind 'type', 'value' in 'Claim(string type, string value)'; cannot bind 'type', 'value', 'valueType' in 'Claim(string type, string value, string valueType)'; cannot bind 'type', 'value', 'valueType', 'issuer' in 'Claim(string type, string value, string valueType, string issuer)'; cannot bind 'type', 'value', 'valueType', 'issuer', 'originalIssuer' in 'Claim(string type, string value, string valueType, string issuer, string originalIssuer)'; cannot bind 'type', 'value', 'valueType', 'issuer', 'originalIssuer', 'subject' in 'Claim(string type, string value, string valueType, string issuer, string originalIssuer, ClaimsIdentity subject)'; cannot bind 'type', 'value', 'valueType', 'issuer', 'originalIssuer', 'subject', 'propertyKey', 'propertyValue' in 'Claim(string type, string value, string valueType, string issuer, string originalIssuer, ClaimsIdentity subject, string propertyKey, string propertyValue)'; cannot bind 'other' in 'Claim(Claim other)'; cannot bind 'other', 'subject' in 'Claim(Claim other, ClaimsIdentity subject)'.
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.ConstructorBindingConvention.ProcessModelFinalized(IConventionModelBuilder modelBuilder, IConventionContext`1 context)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ImmediateConventionScope.OnModelFinalized(IConventionModelBuilder modelBuilder)
   at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.OnModelFinalized(IConventionModelBuilder modelBuilder)
   at Microsoft.EntityFrameworkCore.Metadata.Internal.Model.FinalizeModel()
   at Microsoft.EntityFrameworkCore.ModelBuilder.FinalizeModel()
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.CreateModel(DbContext context, IConventionSetBuilder conventionSetBuilder)
   at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.GetModel(DbContext context, IConventionSetBuilder conventionSetBuilder)
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel()
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model()
   at Microsoft.EntityFrameworkCore.Infrastructure.EntityFrameworkServicesBuilder.<>c.<TryAddCoreServices>b__7_3(IServiceProvider p)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
   at Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies()
   at Microsoft.EntityFrameworkCore.DbContext.get_InternalServiceProvider()
   at Microsoft.EntityFrameworkCore.DbContext.Microsoft.EntityFrameworkCore.Infrastructure.IInfrastructure<System.IServiceProvider>.get_Instance()
   at Microsoft.EntityFrameworkCore.Infrastructure.Internal.InfrastructureExtensions.GetService[TService](IInfrastructure`1 accessor)
   at Microsoft.EntityFrameworkCore.Infrastructure.AccessorExtensions.GetService[TService](IInfrastructure`1 accessor)
   at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(Func`1 factory)
   at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(String contextType)
   at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.AddMigration(String name, String outputDir, String contextType)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigration.<>c__DisplayClass0_0.<.ctor>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.<Execute>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
No suitable constructor found for entity type 'Claim'. The following constructors had parameters that could not be bound to properties of the entity type: cannot bind 'reader' in 'Claim(BinaryReader reader)'; cannot bind 'reader', 'subject' in 'Claim(BinaryReader reader, ClaimsIdentity subject)'; cannot bind 'type', 'value' in 'Claim(string type, string value)'; cannot bind 'type', 'value', 'valueType' in 'Claim(string type, string value, string valueType)'; cannot bind 'type', 'value', 'valueType', 'issuer' in 'Claim(string type, string value, string valueType, string issuer)'; cannot bind 'type', 'value', 'valueType', 'issuer', 'originalIssuer' in 'Claim(string type, string value, string valueType, string issuer, string originalIssuer)'; cannot bind 'type', 'value', 'valueType', 'issuer', 'originalIssuer', 'subject' in 'Claim(string type, string value, string valueType, string issuer, string originalIssuer, ClaimsIdentity subject)'; cannot bind 'type', 'value', 'valueType', 'issuer', 'originalIssuer', 'subject', 'propertyKey', 'propertyValue' in 'Claim(string type, string value, string valueType, string issuer, string originalIssuer, ClaimsIdentity subject, string propertyKey, string propertyValue)'; cannot bind 'other' in 'Claim(Claim other)'; cannot bind 'other', 'subject' in 'Claim(Claim other, ClaimsIdentity subject)'.

Excluding the above seeding method, database migration works really well. As soon as I call the seeding method in OnModelCreating method in ConfigurationDbContext class it fails with the above error.

Can anyone spot where I'm going wrong here???

I'll be looking forward for all your replies.

Thanks in advance,

Sam

You should use types on IdentityServer4.EntityFramework.Entities , you have a mix of models and entities in code, try to remove using IdentityServer4.Models; to get a clear understanding of what is entity and what is model. Once you used entities properly you will see that for example ApiResource doesn't have a property as ApiSecrets , it is Secrets .

There is another way to do initialize the DB by adding a method ob startup.cs , sth like:

private void InitializeDatabase(IApplicationBuilder app)
{
    using (var serviceScope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
    {
        serviceScope.ServiceProvider.GetRequiredService<PersistedGrantDbContext>().Database.Migrate();

        var context = serviceScope.ServiceProvider.GetRequiredService<ConfigurationDbContext>();
        context.Database.Migrate();
        if (!context.Clients.Any())
        {
            foreach (var client in Config.Clients)
            {
                context.Clients.Add(client.ToEntity());
            }
            context.SaveChanges();
        }

        if (!context.IdentityResources.Any())
        {
            foreach (var resource in Config.Ids)
            {
                context.IdentityResources.Add(resource.ToEntity());
            }
            context.SaveChanges();
        }

        if (!context.ApiResources.Any())
        {
            foreach (var resource in Config.Apis)
            {
                context.ApiResources.Add(resource.ToEntity());
            }
            context.SaveChanges();
        }
    }
}

and call it like this;

public void Configure(IApplicationBuilder app)
{
    // this will do the initial DB population
    InitializeDatabase(app);

    // the rest of the code that was already here
    // ...
}

Read more here

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM