Identityazuretable
This project provides a high performance cloud solution for ASP.NET Identity Core using Azure Table storage replacing the Entity Framework / MSSQL provider.
Technical Overview
ElCamino.AspNetCore.Identity.AzureTable <= 1.7
High Level Dependencies
ElCamino.AspNet.Identity.AzureTable.dll acts as the data access layer under the Microsoft.AspNet.Identity.Core.dll classes UserManager and RoleManager by implementing the necessary interfaces on the UserStore and RoleStore respectively. These classes consume the IdentityCloudContext and the other Identity Model classes described below to persist the user and role information according to the business logic dictated by the respective UserManager and RoleManager classes.
UserStore and RoleStore Classes
IdentityCloudContext and Connections
IdentityCloudContext that enables access to the Azure Table storage service and exposes the tables.
The IdentityCloudContext default constructor will look for the IdentityConfigurationSection in the app or web.config which is new in version 1.2.9.0. If this configuration section is not found, the storage connection string under the AppSettings key "StorageConnectionString" which is a deprecated option that will be phased out in lieu of the configuration section or the new IdentityCloudContext(IdentityConfiguration config) overload. The new IdentityConfiguration class is Json serializable for ease of loading/saving these settings.
New in 1.2.9.0 - use the new TablePrefix property to set a naming prefix for the azure tables that are using in the storage account. This enables multi-tenant support per storage account via configuration option for table name prefixing. e.g. Table prefix 'My' uses tables, MyAspNetIndex, MyAspNetRoles, MyAspNetUsers. This is an optional field, can be set to string.empty or left unset.
Example of using the new configuration section:
<configSections>
<section name="elcaminoIdentityConfiguration"
type="ElCamino.AspNet.Identity.AzureTable.Configuration.IdentityConfigurationSection,ElCamino.AspNet.Identity.AzureTable " />
</configSections>
<elcaminoIdentityConfiguration tablePrefix=""
storageConnectionString="UseDevelopmentStorage=true" />
Warning
The following appSettings configuration option has been deprecated in 1.2.9.0.
A custom AppSettings key can be passed in the overloaded constructor IdentityCloudContext(string appSettingsKey). If the appSettingsKey is not found, the literal string will be assumed to be the connection string.
For example, the default local connection string to the Azure Storage Emulator.
<configuration>
<appSettings>
...
<add key="StorageConnectionString"
value="UseDevelopmentStorage=true" />
Identity Model to Azure Table Relationships
AspNetUsers
Identity Model | PartitionKey | RowKey | Cardinality |
---|---|---|---|
IdentityUser | Escaped(UserName) | Escaped(UserName) | 1 per user |
IdentityUserClaim | Escaped(UserName) | Escaped(ClaimType, ClaimValue) | 0 to Many per user |
IdentityUserLogin | Escaped(UserName) | Escaped(LoginProvider, ProviderKey) | 0 to Many per user |
IdentityUserRole | Escaped(UserName) | Escaped(RoleName) | 0 to Many per user |
AspNetIndex
Identity Model | Type | PartitionKey | RowKey | Id | Cardinality |
---|---|---|---|---|---|
IdentityUserIndex | User Email Index | Escaped(User Email) | Escaped(UserName) | Escaped(UserName) | 0 or 1 per user |
IdentityUserIndex | User Login Index | Escaped(LoginProvider, ProviderKey) | Escaped(LoginProvider, ProviderKey) | Escaped(UserName) | 0 to Many per user |
AspNetRoles
Identity Model | PartitionKey | RowKey |
---|---|---|
IdentityRole | Escaped(First Char of RoleName) | Escaped(RoleName) |
The properties of the respective identity model class are stored as a field in the table unless marked with the ignore attribute. Inheriting and extending these classes one can add fields whenever your extended class is saved. Also, the Escaped() psydo-code is a reference to the respective methods found in the KeyHelper class.
Performance
The AspNetUsers table is designed to keep all of the user's data in a single table and in a table partition for each user. This results in a single query using the user's id (partition key) to get all of the data in a single query when the user's id is known. The user's id is an 'Escaped' version of the username and the traditional guid is not used. This makes the UserStore.FindByUserNameAsync() and UserStoreFindByUserNameAsync() use the same query. When the user id is not known, the AspNetIndex table is queried first either by user's email UserStore.FindByEmailAsync() or external login information UserStore.FindAsync() to get the user's id to then query by user id for the complete user information. The AspNextIndex is always queried by partition and rowkey making that query extremely fast. See above for the details of the AspNetIndex partition and rowkey strategy.
AspNetRoles table also uses a composite of the RoleName for the partition and row keys making it possible query the table by its primary key optimizing performance.
Testing
A full suite of integration tests against this assembly ElCamino.AspNet.Identity.AzureTable.Tests.csproj
Release Management
- Full suite of integration tests against this assembly at 100% pass rate against the Azure Local Emulator and against a live Azure Storage account. 100% pass rate is required before release. The tests are at about 99% code coverage currently and will work to keep the up.
- Releases available on NuGet and are strong name signed. Binaries are available for download from this site.
A blog for modern software development
Software as a Service
Optic Nerve AI
No code, first class import/publish with Azure, Google cloud custom vision AI services.