SphericalCom.AspNetCore.Identity.CosmosDB 8.0.7

dotnet add package SphericalCom.AspNetCore.Identity.CosmosDB --version 8.0.7                
NuGet\Install-Package SphericalCom.AspNetCore.Identity.CosmosDB -Version 8.0.7                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="SphericalCom.AspNetCore.Identity.CosmosDB" Version="8.0.7" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add SphericalCom.AspNetCore.Identity.CosmosDB --version 8.0.7                
#r "nuget: SphericalCom.AspNetCore.Identity.CosmosDB, 8.0.7"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install SphericalCom.AspNetCore.Identity.CosmosDB as a Cake Addin
#addin nuget:?package=SphericalCom.AspNetCore.Identity.CosmosDB&version=8.0.7

// Install SphericalCom.AspNetCore.Identity.CosmosDB as a Cake Tool
#tool nuget:?package=SphericalCom.AspNetCore.Identity.CosmosDB&version=8.0.7                

SphericalCom.AspNetCore.Identity.CosmosDB

A no-frills, close-to-spec implementation of the ASP.NET Core Identity database for CosmosDB using EntityFrameworkCore, as non-intrusive as possible and designed for ASP.NET 8.

Inspired by MoonriseSoftware's great AspNetCore.Identity.CosmosDB, I decided to create another implementation of the AspNetCore Identity provider using CosmosDB through EntityFrameworkCode, while seeking to avoid the following:

  • Exiting the conventions set by the current .NET 8 templates or CosmosDB guidance
  • Including outdated/proprietary code (such as a library for DuendeSoftware's IdentityServer)
  • Writing any SQL code, potentially introducing undesired behavior

And after thorough research, the Identity project left all the pieces in place to do this efficiently, by overriding the IdentityDbContext's model creation. Taking this approach minimized the work necessary to implement the library, and thus limited the possibilities for introducing behavior unexpected from the standard Identity model.

Installation

For this we're assuming you have an existing ASP.NET core Identity application working with the default database provider (SqlServer). If this is not the case, please refer to the documentation, as their tutorials are better than anything I can come up with here.

Nuget package

A nuget package can be found at PENDING PACKAGE LINK. Installing the latest stable will allow for usage of the project. Please update all of your project dependencies, as the nuget package uses the latest stable versions of the packages it requires:

  • Microsoft.AspNetCore.Identity.EntityFrameworkCore
  • Microsoft.EntityFrameworkCore.Cosmos
  • Microsoft.Extensions.Identity.Core

DbContext

The default applications provide a DbContext class for you to modify: ApplicationDbContext. This, by default, inherits from IdentityDbContext. This is exemplified as follows:

//Data/ApplicationDbContext.cs
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;

namespace YourApplication.Data;
public class ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : IdentityDbContext<ApplicationUser>(options)
{
}

We will instead inherit from our new CosmosIdentityDbContext to override the model creation with one compatible with CosmosDB.

//Data/ApplicationDbContext.cs
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
// Ensure to add a reference to our package.
using SphericalCom.AspNetCore.Identity.CosmosDB;

namespace YourApplication.Data;
public class ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : CosmosIdentityDbContext<ApplicationUser>(options)
{
}

Database connection

We will now proceed to instruct EFCore to use the CosmosDB connector. If in doubt, refer to the documentation relevant to the connector. For development, we used the CosmosDB Emulator for Windows, but feel free to use a real CosmosDB account.

By default, a DbContext is registered as follows for SqlServer:

//Program.cs
...
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(connectionString));

We will instead ask it to use CosmosDb, feel free to configure the connection as necessary. Ensure your database name is not used within your storage account or you may face issues. The database should be used exclusively for this application, and tables should not be messed with. Existing alongside other databases is OK.

Remember to get a ConnectionString from somewhere (likely your configuration/secrets storage) or the connection will not succeed. The default database name is OK, and it doesn't have to be stored in CosmosDb:Database, so you do you.

//Program.cs
...
var connectionString = builder.Configuration.GetConnectionString("CosmosEmulator") ?? throw new InvalidOperationException("Connection string for CosmosDB not found.");
var databaseName = builder.Configuration.GetValue<string>("CosmosDb:Database") ?? "AspNetCoreIdentity";
builder.Services.AddDbContext<ApplicationDbContext>(dbContextOptions =>
    dbContextOptions.UseCosmos(connectionString, databaseName));
...

Initializing the database

Now, assuming this is your first time setting up the database for Identity, you're going to need to ensure it exists before we start using it. As Cosmos does not support migrations, the easiest way to do this is to insert the following block of code before your app starts running (but after it has been built):

//Program.cs
...
using (var scope = app.Services.CreateScope())
using (var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>())
    context.Database.EnsureCreated();

app.Run();
...

This will, in a nutshell, create a new scope to allow creating an instance of your DbContext, and then ask it to ensure the database is ready. This is done before app.Run() to ensure anything that needs the database will not get ahead of us. While not recommended, you can instead create the database and containers manually, see the source to identify the required names.

Support

I created this mainly as a personal need, so I will try and keep it mostly up to date. Depending on any future changes to Identity on .NET 9 major changes may be necessary (although it seems highly unlikely), and I may or may not wish to make said changes.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
8.0.7 88 7/31/2024

Nuget packaging