UserManager используется с различными хранилищами (UserStore, UserEmailStore, UserClaimStore, UserLockoutStore и т. Д.)
Я пытаюсь реализовать UserStore, но я хотел бы также реализовать UserEmailStore и UserLockoutStore и другие. Как я заметил, все User*Store основаны на UserStore, никаких проблем. Но я заглянул в UserManager и обнаружил для меня странную вещь. Вы можете добавить несколько типов хранилищ в UserManager, но всегда только один. Но UserManager может работать со всеми из них в зависимости от того, какой тип вы ввели.
Пример Fox-метода GetLockoutEndDateAsync из UserManager
public virtual async Task<DateTimeOffset?> GetLockoutEndDateAsync(TUser user)
{
this.ThrowIfDisposed();
IUserLockoutStore<TUser> userLockoutStore = this.GetUserLockoutStore();
if ((object) user == null)
throw new ArgumentNullException("user");
TUser user1 = user;
CancellationToken cancellationToken = this.CancellationToken;
return await userLockoutStore.GetLockoutEndDateAsync(user1, cancellationToken);
}
Метод this.GetUserLockoutStore выглядит следующим образом
internal IUserLockoutStore<TUser> GetUserLockoutStore()
{
IUserLockoutStore<TUser> userLockoutStore = this.Store as IUserLockoutStore<TUser>;
if (userLockoutStore != null)
return userLockoutStore;
throw new NotSupportedException(Resources.StoreNotIUserLockoutStore);
}
Есть и другие методы, такие как
- GetEmailStore
- GetPhoneNumberStore
- GetClaimStore
- GetLoginStore
- ...
Таким образом, это означает, что хранилище должно основываться на правильном интерфейсе, который вы хотите использовать.
У меня вопрос, как с этим бороться? Должен ли я реализовать одно хранилище на основе всех возможных интерфейсов User*Store? Или вы можете предложить другое решение?
заранее спасибо
1 ответ
Да, реализация необходимых интерфейсов в виде "функций" в одном хранилище - это простой способ сделать это, а также способ реализации поставщика ASP.NET Core Identity EF Core (см. Здесь).
/// <summary>
/// Represents a new instance of a persistence store for the specified user and role types.
/// </summary>
/// <typeparam name="TUser">The type representing a user.</typeparam>
/// <typeparam name="TRole">The type representing a role.</typeparam>
/// <typeparam name="TContext">The type of the data context class used to access the store.</typeparam>
/// <typeparam name="TKey">The type of the primary key for a role.</typeparam>
/// <typeparam name="TUserClaim">The type representing a claim.</typeparam>
/// <typeparam name="TUserRole">The type representing a user role.</typeparam>
/// <typeparam name="TUserLogin">The type representing a user external login.</typeparam>
/// <typeparam name="TUserToken">The type representing a user token.</typeparam>
/// <typeparam name="TRoleClaim">The type representing a role claim.</typeparam>
public abstract class UserStore<TUser, TRole, TContext, TKey, TUserClaim, TUserRole, TUserLogin, TUserToken, TRoleClaim> :
IUserLoginStore<TUser>,
IUserRoleStore<TUser>,
IUserClaimStore<TUser>,
IUserPasswordStore<TUser>,
IUserSecurityStampStore<TUser>,
IUserEmailStore<TUser>,
IUserLockoutStore<TUser>,
IUserPhoneNumberStore<TUser>,
IQueryableUserStore<TUser>,
IUserTwoFactorStore<TUser>,
IUserAuthenticationTokenStore<TUser>
where TUser : IdentityUser<TKey, TUserClaim, TUserRole, TUserLogin>
where TRole : IdentityRole<TKey, TUserRole, TRoleClaim>
where TContext : DbContext
where TKey : IEquatable<TKey>
where TUserClaim : IdentityUserClaim<TKey>
where TUserRole : IdentityUserRole<TKey>
where TUserLogin : IdentityUserLogin<TKey>
where TUserToken : IdentityUserToken<TKey>
where TRoleClaim : IdentityRoleClaim<TKey>
{
}
Вам нужно только реализовать интерфейсы, которые вы собираетесь поддерживать, и не включать остальные.
Если по какой-либо причине (принцип единой ответственности) это невозможно (т. Е. Потому, что вам нужно использовать совершенно другой тип базы данных или какой-либо веб-сервис или Active Directory для него), то вы можете реализовать отдельные хранилища и использовать шаблон фасада для обтекания. это и вводить ваши отдельные магазины в фасад и вводить фасад.
Но это больше работы и требует больше настройки DI, чтобы сделать это. Но выполнимо.