From 57a25d080d1d0337b3b2dd8a2906f74a6e94370c Mon Sep 17 00:00:00 2001 From: Hao Kung Date: Tue, 17 Jan 2017 12:45:45 -0800 Subject: [PATCH] AddEFStores: Infer generics from DbContext --- .../IdentityDbContext.cs | 3 +- ...dentityEntityFrameworkBuilderExtensions.cs | 53 +++--- .../IdentityUser.cs | 10 +- .../Properties/Resources.Designer.cs | 8 +- .../Resources.resx | 4 +- .../RoleStore.cs | 22 +-- .../UserStore.cs | 177 ++++++------------ .../exceptions.net45.json | 56 ++++++ .../exceptions.netcore.json | 56 ++++++ .../InMemoryContext.cs | 2 +- .../InMemoryStoreWithGenericsTest.cs | 31 ++- .../SqlStoreTestBase.cs | 19 ++ .../UserStoreWithGenericsTest.cs | 15 +- 13 files changed, 268 insertions(+), 188 deletions(-) create mode 100644 src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/exceptions.net45.json create mode 100644 src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/exceptions.netcore.json diff --git a/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/IdentityDbContext.cs b/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/IdentityDbContext.cs index 4ad6fde708..2a409a4820 100644 --- a/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/IdentityDbContext.cs +++ b/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/IdentityDbContext.cs @@ -82,7 +82,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore /// The type of the role claim object. /// The type of the user token object. public abstract class IdentityDbContext : DbContext - where TUser : IdentityUser + where TUser : IdentityUser where TRole : IdentityRole where TKey : IEquatable where TUserClaim : IdentityUserClaim @@ -162,6 +162,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore b.HasMany(u => u.Claims).WithOne().HasForeignKey(uc => uc.UserId).IsRequired(); b.HasMany(u => u.Logins).WithOne().HasForeignKey(ul => ul.UserId).IsRequired(); b.HasMany(u => u.Roles).WithOne().HasForeignKey(ur => ur.UserId).IsRequired(); + b.HasMany(u => u.Tokens).WithOne().HasForeignKey(ut => ut.UserId).IsRequired(); }); builder.Entity(b => diff --git a/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/IdentityEntityFrameworkBuilderExtensions.cs b/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/IdentityEntityFrameworkBuilderExtensions.cs index 0c92871186..6a25296f53 100644 --- a/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/IdentityEntityFrameworkBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/IdentityEntityFrameworkBuilderExtensions.cs @@ -24,60 +24,53 @@ namespace Microsoft.Extensions.DependencyInjection public static IdentityBuilder AddEntityFrameworkStores(this IdentityBuilder builder) where TContext : DbContext { - var keyType = InferKeyType(typeof(TContext)); - AddStores(builder.Services, builder.UserType, builder.RoleType, typeof(TContext), keyType); + AddStores(builder.Services, builder.UserType, builder.RoleType, typeof(TContext)); return builder; } - /// - /// Adds an Entity Framework implementation of identity information stores. - /// - /// The Entity Framework database context to use. - /// The type of the primary key used for the users and roles. - /// The instance this method extends. - /// The instance this method extends. - public static IdentityBuilder AddEntityFrameworkStores(this IdentityBuilder builder) - where TContext : DbContext - where TKey : IEquatable + private static void AddStores(IServiceCollection services, Type userType, Type roleType, Type contextType) { - AddStores(builder.Services, builder.UserType, builder.RoleType, typeof(TContext), typeof(TKey)); - return builder; - } - - private static void AddStores(IServiceCollection services, Type userType, Type roleType, Type contextType, Type keyType) - { - var identityUserType = typeof(IdentityUser<>).MakeGenericType(keyType); - if (!identityUserType.GetTypeInfo().IsAssignableFrom(userType.GetTypeInfo())) + var identityUserType = FindGenericBaseType(userType, typeof(IdentityUser<,,,,>)); + if (identityUserType == null) { throw new InvalidOperationException(Resources.NotIdentityUser); } - var identityRoleType = typeof(IdentityRole<>).MakeGenericType(keyType); - if (!identityRoleType.GetTypeInfo().IsAssignableFrom(roleType.GetTypeInfo())) + var identityRoleType = FindGenericBaseType(roleType, typeof(IdentityRole<,,>)); + if (identityRoleType == null) { throw new InvalidOperationException(Resources.NotIdentityRole); } + services.TryAddScoped( typeof(IUserStore<>).MakeGenericType(userType), - typeof(UserStore<,,,>).MakeGenericType(userType, roleType, contextType, keyType)); + typeof(UserStore<,,,,,,,,>).MakeGenericType(userType, roleType, contextType, + identityUserType.GenericTypeArguments[0], + identityUserType.GenericTypeArguments[1], + identityUserType.GenericTypeArguments[2], + identityUserType.GenericTypeArguments[3], + identityUserType.GenericTypeArguments[4], + identityRoleType.GenericTypeArguments[2])); services.TryAddScoped( typeof(IRoleStore<>).MakeGenericType(roleType), - typeof(RoleStore<,,>).MakeGenericType(roleType, contextType, keyType)); + typeof(RoleStore<,,,,>).MakeGenericType(roleType, contextType, + identityRoleType.GenericTypeArguments[0], + identityRoleType.GenericTypeArguments[1], + identityRoleType.GenericTypeArguments[2])); } - private static Type InferKeyType(Type contextType) + private static TypeInfo FindGenericBaseType(Type currentType, Type genericBaseType) { - var type = contextType.GetTypeInfo(); + var type = currentType.GetTypeInfo(); while (type.BaseType != null) { type = type.BaseType.GetTypeInfo(); var genericType = type.IsGenericType ? type.GetGenericTypeDefinition() : null; - if (genericType != null && genericType == typeof(IdentityDbContext<,,>)) + if (genericType != null && genericType == genericBaseType) { - return type.GenericTypeArguments[2]; + return type; } } - // Default is string - return typeof(string); + return null; } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/IdentityUser.cs b/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/IdentityUser.cs index c8c396dcd7..67006f9a4e 100644 --- a/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/IdentityUser.cs +++ b/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/IdentityUser.cs @@ -39,7 +39,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore /// Represents a user in the identity system /// /// The type used for the primary key for the user. - public class IdentityUser : IdentityUser, IdentityUserRole, IdentityUserLogin> + public class IdentityUser : IdentityUser, IdentityUserRole, IdentityUserLogin, IdentityUserToken> where TKey : IEquatable { } @@ -50,7 +50,8 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore /// The type representing a claim. /// The type representing a user role. /// The type representing a user external login. - public class IdentityUser where TKey : IEquatable + /// The type representing a user external login. + public class IdentityUser where TKey : IEquatable { /// /// Initializes a new instance of . @@ -163,6 +164,11 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore /// public virtual ICollection Logins { get; } = new List(); + /// + /// Navigation property for this users tokens. + /// + public virtual ICollection Tokens { get; } = new List(); + /// /// Returns the username for this user. /// diff --git a/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/Properties/Resources.Designer.cs index d9bc0a88a8..9862d64fb6 100644 --- a/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/Properties/Resources.Designer.cs @@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore = new ResourceManager("Microsoft.AspNetCore.Identity.EntityFrameworkCore.Resources", typeof(Resources).GetTypeInfo().Assembly); /// - /// AddEntityFrameworkStores can only be called with a role that derives from IdentityRole<TKey>. If you are specifying more generic arguments, use AddRoleStore<TStore>() where TStore is your custom IRoleStore that uses your generics instead. + /// AddEntityFrameworkStores can only be called with a role that derives from IdentityRole<TKey, TUserRole, TRoleClaim>. /// internal static string NotIdentityRole { @@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore } /// - /// AddEntityFrameworkStores can only be called with a role that derives from IdentityRole<TKey>. If you are specifying more generic arguments, use AddRoleStore<TStore>() where TStore is your custom IRoleStore that uses your generics instead. + /// AddEntityFrameworkStores can only be called with a role that derives from IdentityRole<TKey, TUserRole, TRoleClaim>. /// internal static string FormatNotIdentityRole() { @@ -27,7 +27,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore } /// - /// AddEntityFrameworkStores can only be called with a user that derives from IdentityUser<TKey>. If you are specifying more generic arguments, use IdentityBuilder.AddUserStore<TStore>() where TStore is your custom IUserStore that uses your generics instead. + /// AddEntityFrameworkStores can only be called with a user that derives from IdentityUser<TKey, TUserClaim, TUserRole, TUserLogin, TUserToken>. /// internal static string NotIdentityUser { @@ -35,7 +35,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore } /// - /// AddEntityFrameworkStores can only be called with a user that derives from IdentityUser<TKey>. If you are specifying more generic arguments, use IdentityBuilder.AddUserStore<TStore>() where TStore is your custom IUserStore that uses your generics instead. + /// AddEntityFrameworkStores can only be called with a user that derives from IdentityUser<TKey, TUserClaim, TUserRole, TUserLogin, TUserToken>. /// internal static string FormatNotIdentityUser() { diff --git a/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/Resources.resx b/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/Resources.resx index b46be0a6f2..eb19639109 100644 --- a/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/Resources.resx +++ b/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/Resources.resx @@ -118,11 +118,11 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - AddEntityFrameworkStores can only be called with a role that derives from IdentityRole<TKey>. If you are specifying more generic arguments, use AddRoleStore<TStore>() where TStore is your custom IRoleStore that uses your generics instead. + AddEntityFrameworkStores can only be called with a role that derives from IdentityRole<TKey, TUserRole, TRoleClaim>. error when the role does not derive from IdentityRole - AddEntityFrameworkStores can only be called with a user that derives from IdentityUser<TKey>. If you are specifying more generic arguments, use IdentityBuilder.AddUserStore<TStore>() where TStore is your custom IUserStore that uses your generics instead. + AddEntityFrameworkStores can only be called with a user that derives from IdentityUser<TKey, TUserClaim, TUserRole, TUserLogin, TUserToken>. error when the user does not derive from IdentityUser diff --git a/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/RoleStore.cs b/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/RoleStore.cs index e4febdec32..2baedd84c8 100644 --- a/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/RoleStore.cs +++ b/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/RoleStore.cs @@ -64,17 +64,6 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore /// The . /// The . public RoleStore(TContext context, IdentityErrorDescriber describer = null) : base(context, describer) { } - - /// - /// Creates a entity representing a role claim. - /// - /// The associated role. - /// The associated claim. - /// The role claim entity. - protected override IdentityRoleClaim CreateRoleClaim(TRole role, Claim claim) - { - return new IdentityRoleClaim { RoleId = role.Id, ClaimType = claim.Type, ClaimValue = claim.Value }; - } } /// @@ -85,14 +74,14 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore /// The type of the primary key for a role. /// The type of the class representing a user role. /// The type of the class representing a role claim. - public abstract class RoleStore : + public class RoleStore : IQueryableRoleStore, IRoleClaimStore where TRole : IdentityRole where TKey : IEquatable where TContext : DbContext - where TUserRole : IdentityUserRole - where TRoleClaim : IdentityRoleClaim + where TUserRole : IdentityUserRole, new() + where TRoleClaim : IdentityRoleClaim, new() { /// /// Constructs a new instance of . @@ -458,6 +447,9 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore /// The associated role. /// The associated claim. /// The role claim entity. - protected abstract TRoleClaim CreateRoleClaim(TRole role, Claim claim); + protected virtual TRoleClaim CreateRoleClaim(TRole role, Claim claim) + { + return new TRoleClaim { RoleId = role.Id, ClaimType = claim.Type, ClaimValue = claim.Value }; + } } } diff --git a/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/UserStore.cs b/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/UserStore.cs index f835fd7a46..cac71ac9b6 100644 --- a/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/UserStore.cs +++ b/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/UserStore.cs @@ -69,7 +69,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore /// The type representing a role. /// The type of the data context class used to access the store. /// The type of the primary key for a role. - public class UserStore : UserStore, IdentityUserRole, IdentityUserLogin, IdentityUserToken> + public class UserStore : UserStore, IdentityUserRole, IdentityUserLogin, IdentityUserToken, IdentityRoleClaim> where TUser : IdentityUser where TRole : IdentityRole where TContext : DbContext @@ -81,103 +81,8 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore /// The . /// The . public UserStore(TContext context, IdentityErrorDescriber describer = null) : base(context, describer) { } - - /// - /// Called to create a new instance of a . - /// - /// The associated user. - /// The associated role. - /// - protected override IdentityUserRole CreateUserRole(TUser user, TRole role) - { - return new IdentityUserRole() - { - UserId = user.Id, - RoleId = role.Id - }; - } - - /// - /// Called to create a new instance of a . - /// - /// The associated user. - /// The associated claim. - /// - protected override IdentityUserClaim CreateUserClaim(TUser user, Claim claim) - { - var userClaim = new IdentityUserClaim { UserId = user.Id }; - userClaim.InitializeFromClaim(claim); - return userClaim; - } - - /// - /// Called to create a new instance of a . - /// - /// The associated user. - /// The sasociated login. - /// - protected override IdentityUserLogin CreateUserLogin(TUser user, UserLoginInfo login) - { - return new IdentityUserLogin - { - UserId = user.Id, - ProviderKey = login.ProviderKey, - LoginProvider = login.LoginProvider, - ProviderDisplayName = login.ProviderDisplayName - }; - } - - /// - /// Called to create a new instance of a . - /// - /// The associated user. - /// The associated login provider. - /// The name of the user token. - /// The value of the user token. - /// - protected override IdentityUserToken CreateUserToken(TUser user, string loginProvider, string name, string value) - { - return new IdentityUserToken - { - UserId = user.Id, - LoginProvider = loginProvider, - Name = name, - Value = value - }; - } } - /// - /// Represents a new instance of a persistence store for the specified user and role types. - /// - /// The type representing a user. - /// The type representing a role. - /// The type of the data context class used to access the store. - /// The type of the primary key for a role. - /// The type representing a claim. - /// The type representing a user role. - /// The type representing a user external login. - /// The type representing a user token. - public abstract class UserStore : - UserStore> - where TUser : IdentityUser - where TRole : IdentityRole> - where TContext : DbContext - where TKey : IEquatable - where TUserClaim : IdentityUserClaim - where TUserRole : IdentityUserRole - where TUserLogin : IdentityUserLogin - where TUserToken : IdentityUserToken - { - /// - /// Creates a new instance of . - /// - /// The context used to access the store. - /// The used to describe store errors. - public UserStore(TContext context, IdentityErrorDescriber describer = null) : base(context, describer) { } - } - - /// /// Represents a new instance of a persistence store for the specified user and role types. /// @@ -190,7 +95,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore /// The type representing a user external login. /// The type representing a user token. /// The type representing a role claim. - public abstract class UserStore : + public class UserStore : IUserLoginStore, IUserRoleStore, IUserClaimStore, @@ -204,15 +109,15 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore IUserAuthenticationTokenStore, IUserAuthenticatorKeyStore, IUserTwoFactorRecoveryCodeStore - where TUser : IdentityUser + where TUser : IdentityUser where TRole : IdentityRole where TContext : DbContext where TKey : IEquatable - where TUserClaim : IdentityUserClaim - where TUserRole : IdentityUserRole - where TUserLogin : IdentityUserLogin - where TUserToken : IdentityUserToken - where TRoleClaim : IdentityRoleClaim + where TUserClaim : IdentityUserClaim, new() + where TUserRole : IdentityUserRole, new() + where TUserLogin : IdentityUserLogin, new() + where TUserToken : IdentityUserToken, new() + where TRoleClaim : IdentityRoleClaim, new() { /// /// Creates a new instance of . @@ -249,38 +154,68 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore private DbSet UserTokens { get { return Context.Set(); } } /// - /// Creates a new entity to represent a user role. + /// Called to create a new instance of a . /// - /// - /// + /// The associated user. + /// The associated role. /// - protected abstract TUserRole CreateUserRole(TUser user, TRole role); + protected virtual TUserRole CreateUserRole(TUser user, TRole role) + { + return new TUserRole() + { + UserId = user.Id, + RoleId = role.Id + }; + } /// - /// Create a new entity representing a user claim. + /// Called to create a new instance of a . /// - /// - /// + /// The associated user. + /// The associated claim. /// - protected abstract TUserClaim CreateUserClaim(TUser user, Claim claim); + protected virtual TUserClaim CreateUserClaim(TUser user, Claim claim) + { + var userClaim = new TUserClaim { UserId = user.Id }; + userClaim.InitializeFromClaim(claim); + return userClaim; + } /// - /// Create a new entity representing a user login. + /// Called to create a new instance of a . /// - /// - /// + /// The associated user. + /// The sasociated login. /// - protected abstract TUserLogin CreateUserLogin(TUser user, UserLoginInfo login); + protected virtual TUserLogin CreateUserLogin(TUser user, UserLoginInfo login) + { + return new TUserLogin + { + UserId = user.Id, + ProviderKey = login.ProviderKey, + LoginProvider = login.LoginProvider, + ProviderDisplayName = login.ProviderDisplayName + }; + } /// - /// Create a new entity representing a user token. + /// Called to create a new instance of a . /// - /// - /// - /// - /// + /// The associated user. + /// The associated login provider. + /// The name of the user token. + /// The value of the user token. /// - protected abstract TUserToken CreateUserToken(TUser user, string loginProvider, string name, string value); + protected virtual TUserToken CreateUserToken(TUser user, string loginProvider, string name, string value) + { + return new TUserToken + { + UserId = user.Id, + LoginProvider = loginProvider, + Name = name, + Value = value + }; + } /// /// Gets or sets a flag indicating if changes should be persisted after CreateAsync, UpdateAsync and DeleteAsync are called. diff --git a/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/exceptions.net45.json b/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/exceptions.net45.json new file mode 100644 index 0000000000..91be521fc6 --- /dev/null +++ b/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/exceptions.net45.json @@ -0,0 +1,56 @@ +[ + { + "OldTypeId": "public abstract class Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore : Microsoft.AspNetCore.Identity.IUserLoginStore, Microsoft.AspNetCore.Identity.IUserRoleStore, Microsoft.AspNetCore.Identity.IUserClaimStore, Microsoft.AspNetCore.Identity.IUserPasswordStore, Microsoft.AspNetCore.Identity.IUserSecurityStampStore, Microsoft.AspNetCore.Identity.IUserEmailStore, Microsoft.AspNetCore.Identity.IUserLockoutStore, Microsoft.AspNetCore.Identity.IUserPhoneNumberStore, Microsoft.AspNetCore.Identity.IQueryableUserStore, Microsoft.AspNetCore.Identity.IUserTwoFactorStore, Microsoft.AspNetCore.Identity.IUserAuthenticationTokenStore where T0 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser where T1 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole> where T2 : Microsoft.EntityFrameworkCore.DbContext where T3 : System.IEquatable where T4 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim where T5 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole where T6 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin where T7 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore : Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken> where T0 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser where T1 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole where T2 : Microsoft.EntityFrameworkCore.DbContext where T3 : System.IEquatable", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser where T0 : System.IEquatable", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin> where T0 : System.IEquatable", + "Kind": "Removal" + }, + { + "OldTypeId": "public static class Microsoft.Extensions.DependencyInjection.IdentityEntityFrameworkBuilderExtensions", + "OldMemberId": "public static new Microsoft.AspNetCore.Identity.IdentityBuilder AddEntityFrameworkStores(this Microsoft.AspNetCore.Identity.IdentityBuilder builder) where T0 : Microsoft.EntityFrameworkCore.DbContext where T1 : System.IEquatable", + "Kind": "Removal" + }, + { + "OldTypeId": "public abstract class Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityDbContext : Microsoft.EntityFrameworkCore.DbContext where T0 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser where T1 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole where T2 : System.IEquatable where T3 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim where T4 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole where T5 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin where T6 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim where T7 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore : Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken> where T0 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser where T1 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole where T2 : Microsoft.EntityFrameworkCore.DbContext where T3 : System.IEquatable", + "OldMemberId": "protected override Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin CreateUserLogin(T0 user, Microsoft.AspNetCore.Identity.UserLoginInfo login)", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore : Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken> where T0 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser where T1 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole where T2 : Microsoft.EntityFrameworkCore.DbContext where T3 : System.IEquatable", + "OldMemberId": "protected override Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim CreateUserClaim(T0 user, System.Security.Claims.Claim claim)", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore : Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken> where T0 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser where T1 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole where T2 : Microsoft.EntityFrameworkCore.DbContext where T3 : System.IEquatable", + "OldMemberId": "protected override Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole CreateUserRole(T0 user, T1 role)", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Identity.EntityFrameworkCore.RoleStore : Microsoft.AspNetCore.Identity.EntityFrameworkCore.RoleStore, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim> where T0 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole where T1 : Microsoft.EntityFrameworkCore.DbContext where T2 : System.IEquatable", + "OldMemberId": "protected override Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim CreateRoleClaim(T0 role, System.Security.Claims.Claim claim)", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore : Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken> where T0 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser where T1 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole where T2 : Microsoft.EntityFrameworkCore.DbContext where T3 : System.IEquatable", + "OldMemberId": "protected override Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken CreateUserToken(T0 user, System.String loginProvider, System.String name, System.String value)", + "Kind": "Removal" + }, + { + "OldTypeId": "public abstract class Microsoft.AspNetCore.Identity.EntityFrameworkCore.RoleStore : Microsoft.AspNetCore.Identity.IQueryableRoleStore, Microsoft.AspNetCore.Identity.IRoleClaimStore where T0 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole where T1 : Microsoft.EntityFrameworkCore.DbContext where T2 : System.IEquatable where T3 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole where T4 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim", + "Kind": "Removal" + } +] diff --git a/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/exceptions.netcore.json b/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/exceptions.netcore.json new file mode 100644 index 0000000000..91be521fc6 --- /dev/null +++ b/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/exceptions.netcore.json @@ -0,0 +1,56 @@ +[ + { + "OldTypeId": "public abstract class Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore : Microsoft.AspNetCore.Identity.IUserLoginStore, Microsoft.AspNetCore.Identity.IUserRoleStore, Microsoft.AspNetCore.Identity.IUserClaimStore, Microsoft.AspNetCore.Identity.IUserPasswordStore, Microsoft.AspNetCore.Identity.IUserSecurityStampStore, Microsoft.AspNetCore.Identity.IUserEmailStore, Microsoft.AspNetCore.Identity.IUserLockoutStore, Microsoft.AspNetCore.Identity.IUserPhoneNumberStore, Microsoft.AspNetCore.Identity.IQueryableUserStore, Microsoft.AspNetCore.Identity.IUserTwoFactorStore, Microsoft.AspNetCore.Identity.IUserAuthenticationTokenStore where T0 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser where T1 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole> where T2 : Microsoft.EntityFrameworkCore.DbContext where T3 : System.IEquatable where T4 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim where T5 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole where T6 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin where T7 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore : Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken> where T0 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser where T1 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole where T2 : Microsoft.EntityFrameworkCore.DbContext where T3 : System.IEquatable", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser where T0 : System.IEquatable", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin> where T0 : System.IEquatable", + "Kind": "Removal" + }, + { + "OldTypeId": "public static class Microsoft.Extensions.DependencyInjection.IdentityEntityFrameworkBuilderExtensions", + "OldMemberId": "public static new Microsoft.AspNetCore.Identity.IdentityBuilder AddEntityFrameworkStores(this Microsoft.AspNetCore.Identity.IdentityBuilder builder) where T0 : Microsoft.EntityFrameworkCore.DbContext where T1 : System.IEquatable", + "Kind": "Removal" + }, + { + "OldTypeId": "public abstract class Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityDbContext : Microsoft.EntityFrameworkCore.DbContext where T0 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser where T1 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole where T2 : System.IEquatable where T3 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim where T4 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole where T5 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin where T6 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim where T7 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore : Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken> where T0 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser where T1 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole where T2 : Microsoft.EntityFrameworkCore.DbContext where T3 : System.IEquatable", + "OldMemberId": "protected override Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin CreateUserLogin(T0 user, Microsoft.AspNetCore.Identity.UserLoginInfo login)", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore : Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken> where T0 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser where T1 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole where T2 : Microsoft.EntityFrameworkCore.DbContext where T3 : System.IEquatable", + "OldMemberId": "protected override Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim CreateUserClaim(T0 user, System.Security.Claims.Claim claim)", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore : Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken> where T0 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser where T1 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole where T2 : Microsoft.EntityFrameworkCore.DbContext where T3 : System.IEquatable", + "OldMemberId": "protected override Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole CreateUserRole(T0 user, T1 role)", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Identity.EntityFrameworkCore.RoleStore : Microsoft.AspNetCore.Identity.EntityFrameworkCore.RoleStore, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim> where T0 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole where T1 : Microsoft.EntityFrameworkCore.DbContext where T2 : System.IEquatable", + "OldMemberId": "protected override Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim CreateRoleClaim(T0 role, System.Security.Claims.Claim claim)", + "Kind": "Removal" + }, + { + "OldTypeId": "public class Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore : Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken> where T0 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser where T1 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole where T2 : Microsoft.EntityFrameworkCore.DbContext where T3 : System.IEquatable", + "OldMemberId": "protected override Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken CreateUserToken(T0 user, System.String loginProvider, System.String name, System.String value)", + "Kind": "Removal" + }, + { + "OldTypeId": "public abstract class Microsoft.AspNetCore.Identity.EntityFrameworkCore.RoleStore : Microsoft.AspNetCore.Identity.IQueryableRoleStore, Microsoft.AspNetCore.Identity.IRoleClaimStore where T0 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole where T1 : Microsoft.EntityFrameworkCore.DbContext where T2 : System.IEquatable where T3 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole where T4 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim", + "Kind": "Removal" + } +] diff --git a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/InMemoryContext.cs b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/InMemoryContext.cs index bfbf9fdc6c..df1144adae 100644 --- a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/InMemoryContext.cs +++ b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/InMemoryContext.cs @@ -36,7 +36,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test } public abstract class InMemoryContext : IdentityDbContext - where TUser : IdentityUser + where TUser : IdentityUser where TRole : IdentityRole where TKey : IEquatable where TUserClaim : IdentityUserClaim diff --git a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/InMemoryStoreWithGenericsTest.cs b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/InMemoryStoreWithGenericsTest.cs index 689689728b..dd0e404be6 100644 --- a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/InMemoryStoreWithGenericsTest.cs +++ b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test/InMemoryStoreWithGenericsTest.cs @@ -188,7 +188,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test #region Generic Type defintions - public class IdentityUserWithGenerics : IdentityUser + public class IdentityUserWithGenerics : IdentityUser { public IdentityUserWithGenerics() { @@ -196,7 +196,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test } } - public class UserStoreWithGenerics : UserStore + public class UserStoreWithGenerics : UserStore { public string LoginContext { get; set; } @@ -245,7 +245,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test } } - public class RoleStoreWithGenerics : RoleStore> + public class RoleStoreWithGenerics : RoleStore { private string _loginContext; public RoleStoreWithGenerics(InMemoryContextWithGenerics context, string loginContext) : base(context) @@ -253,10 +253,6 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test _loginContext = loginContext; } - protected override IdentityRoleClaim CreateRoleClaim(MyIdentityRole role, Claim claim) - { - return new IdentityRoleClaim { RoleId = role.Id, ClaimType = claim.Type, ClaimValue = claim.Value }; - } } public class IdentityUserClaimWithIssuer : IdentityUserClaim @@ -276,12 +272,29 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test } } + public class IdentityRoleClaimWithIssuer : IdentityRoleClaim + { + public string Issuer { get; set; } + + public override Claim ToClaim() + { + return new Claim(ClaimType, ClaimValue, null, Issuer); + } + + public override void InitializeFromClaim(Claim other) + { + ClaimValue = other.Value; + ClaimType = other.Type; + Issuer = other.Issuer; + } + } + public class IdentityUserRoleWithDate : IdentityUserRole { public DateTime Created { get; set; } } - public class MyIdentityRole : IdentityRole> + public class MyIdentityRole : IdentityRole { public MyIdentityRole() : base() { @@ -305,7 +318,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test public string Context { get; set; } } - public class InMemoryContextWithGenerics : InMemoryContext, IdentityUserTokenWithStuff> + public class InMemoryContextWithGenerics : InMemoryContext { public InMemoryContextWithGenerics(DbContextOptions options) : base(options) { } diff --git a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/SqlStoreTestBase.cs b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/SqlStoreTestBase.cs index 06cc83402c..5a78f6c50d 100644 --- a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/SqlStoreTestBase.cs +++ b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/SqlStoreTestBase.cs @@ -218,6 +218,25 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test Assert.Equal(0, roles.Count()); } + [ConditionalFact] + [FrameworkSkipCondition(RuntimeFrameworks.Mono)] + [OSSkipCondition(OperatingSystems.Linux)] + [OSSkipCondition(OperatingSystems.MacOSX)] + public async Task DeleteUserRemovesTokensTest() + { + // Need fail if not empty? + var userMgr = CreateManager(); + var user = CreateTestUser(); + IdentityResultAssert.IsSuccess(await userMgr.CreateAsync(user)); + IdentityResultAssert.IsSuccess(await userMgr.SetAuthenticationTokenAsync(user, "provider", "test", "value")); + + Assert.Equal("value", await userMgr.GetAuthenticationTokenAsync(user, "provider", "test")); + + IdentityResultAssert.IsSuccess(await userMgr.DeleteAsync(user)); + + Assert.Null(await userMgr.GetAuthenticationTokenAsync(user, "provider", "test")); + } + [ConditionalFact] [FrameworkSkipCondition(RuntimeFrameworks.Mono)] diff --git a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/UserStoreWithGenericsTest.cs b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/UserStoreWithGenericsTest.cs index e8b0587dfb..89ba53590b 100644 --- a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/UserStoreWithGenericsTest.cs +++ b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/UserStoreWithGenericsTest.cs @@ -87,7 +87,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test public void AddEntityFrameworkStoresWithInvalidUserThrows() { var services = new ServiceCollection(); - var builder = services.AddIdentity(); + var builder = services.AddIdentity(); var e = Assert.Throws(() => builder.AddEntityFrameworkStores()); Assert.Contains("AddEntityFrameworkStores", e.Message); } @@ -96,11 +96,20 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test public void AddEntityFrameworkStoresWithInvalidRoleThrows() { var services = new ServiceCollection(); - var builder = services.AddIdentity(); + var builder = services.AddIdentity(); var e = Assert.Throws(() => builder.AddEntityFrameworkStores()); Assert.Contains("AddEntityFrameworkStores", e.Message); } + [Fact] + public void AddEntityFrameworkStoresWithMismatchedUserRoleThrows() + { + var services = new ServiceCollection(); + var builder = services.AddIdentity(); + var e = Assert.Throws(() => builder.AddEntityFrameworkStores()); + Assert.Contains("violates the constraint of type 'TRole'", e.Message); + } + [Fact] public async Task CanAddRemoveUserClaimWithIssuer() { @@ -209,7 +218,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test #region Generic Type defintions - public class IdentityUserWithGenerics : IdentityUser + public class IdentityUserWithGenerics : IdentityUser { public IdentityUserWithGenerics() {