Identity Server: Using Entity Framework Core for Configuration Data

This post is a continuation of a series of posts that follow my initial looking into using IdentityServer4 in ASP.NET Core with an API and an Angular front end. The following are the related posts.

Identity Server: Introduction
Identity Server: Sample Exploration and Initial Project Setup
Identity Server: Interactive Login using MVC
Identity Server: From Implicit to Hybrid Flow
Identity Server: Using ASP.NET Core Identity
Identity Server: Using Entity Framework Core for Configuration Data (this post)
Identity Server: Usage from Angular

This post is going to take the existing solution this series has been using and switch from using hard coded configuration data, found in the  Config class of the Identity Application and moving it to a database using Entity Framework Core. As with prior entries, this will be following the intent of one of the official quick starts for Using Entity Framework Core for configuration data. This post is fairly different just because our example project already uses entity framework so a lot of steps can be skipped. The starting point of the code can be found here. All the changes in this post will be taking place in the Identity Application.

Identity Application

Thankfully the creators of IdentityServer provide a NuGet package that includes all the bits needed to move configuration data and operational data to Entity Framework Core. Start by added the following NuGet package.

  • IdentityServer4.EntityFramework
Startup

With the above NuGet package installed the  ConfigureServices function of the  Startup class needs to be changed to tell IdentityServer the new place to pull data from. The following is the new version of the  AddIdentityServer call updated to use Entity Framework Core.

Notice that the following have all been replaced by  AddConfigurationStore and  AddOperationalStore.

  • AddInMemoryPersistedGrants
  • AddInMemoryIdentityResources
  • AddInMemoryApiResources
  • AddInMemoryClients

The other thing of note is the  migrationsAssembly and its usage via  options.MigrationsAssembly. This is moving the management of the migrations from the assembly that the contexts are defined to the Identity Application. This is needed in this case since the two contexts in question are defined in a NuGet package.

Migrations

Now that the configuration is done for the new contexts migrations need to be added to them. As always there are two ways to handle this either via the Package Manager Console or from a command prompt. I am going to use the command prompt this round to match the IdentityServer docs. Run the following two commands from the same path as the Identity Application’s csproj file.

This is the first time I have used the  -o argument which controls where the migration is output and following the docs example I am putting the migrations that are for entities outside of the control of the application into a subdirectory. Speaking of the entities being outside of the control of the main application, this means anytime the NuGet package that contains the entity is updated a check will need to be made to see if new migrations are needed.

Database Migrations and Seed Data

Since the  DbContext classes that need migrations run are outside of the control our application if automatic migrations must be handled in a different way than with the identity-related context used previously in this series. Following the official docs, I am going to create an  InitializeDatabase function that will apply any needed migrations as well as add seed data. To do this I am adding a new IdentityServerDatabaseInitialization class in the Data/IdentityServer directory. The following is the full class.

The  InitializeDatabase takes an  IApplicationBuilder in order to be able to control the lifetime of the two  DbContext classes needed. Normally this wouldn’t be needed and the lifetime would be controlled automatically, but since this code is being called from the  Startup class instead of during a request (which is how the DI system does auto scoping) the scope is being created by the  app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope() call.

The  PerformMigrations function pulls the two  DbContext objects from the container and applies migrations. Finally in  SeedData if the  DbSets don’t already contain data then the seed data is pulled from the  Config class and saved to the database.

Back to Startup

In the  Configure function of the  Startup class add the following call to make sure migrations and seed data are run when the application starts.

Wrapping up

With the above changes, the Identity Application is now using the database for all its persistence. The missing bits are of course UI to manage the related data, but those can be built out as needed. The code in its completed state can be found here.

The next steps for this project will be utilizing IdentityServer from Angular in the Client Application instead of the temporary  IdentityController that has had to be used in all the examples so far.

Leave a Reply

Your email address will not be published. Required fields are marked *