Как зарегистрировать пользовательский UserStore & UserManager в DI
Вот моя настройка:
public class ApplicationUser : IdentityUser<Guid>
{
}
public class ApplicationRole : IdentityRole<Guid>
{
}
public class ApplicationUserLogin : IdentityUserLogin<Guid>
{
}
public class ApplicationUserClaim : IdentityUserClaim<Guid>
{
}
public class ApplicationRoleClaim : IdentityRoleClaim<Guid>
{
}
Вот определение моего UserStore
public class ApplicationUserStore : UserStore<ApplicationUser, ApplicationRole, MyContext, Guid>
{
public ApplicationUserStore(MyContext context, IdentityErrorDescriber describer = null)
: base(context, describer)
{
}
}
Вот определение моего UserManager
public class ApplicationUserManager : UserManager<ApplicationUser>
{
public ApplicationUserManager(IUserStore<ApplicationUser> store, IOptions<IdentityOptions> optionsAccessor,
IPasswordHasher<ApplicationUser> passwordHasher, IEnumerable<IUserValidator<ApplicationUser>> userValidators,
IEnumerable<IPasswordValidator<ApplicationUser>> passwordValidators, ILookupNormalizer keyNormalizer,
IdentityErrorDescriber errors, IEnumerable<IUserTokenProvider<ApplicationUser>> tokenProviders,
ILoggerFactory logger, IHttpContextAccessor contextAccessor)
: base(
store, optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors,
tokenProviders, logger, contextAccessor)
{
}
}
Вот определение моего DbContext:
public class MyContext : IdentityDbContext<ApplicationUser, ApplicationRole, Guid>
{
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
}
}
И вот мой Startup.cs
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<MyContext>(options => options.UseSqlServer(Configuration.Get("Data:DbConnection")));
services.AddIdentity<ApplicationUser, ApplicationRole>()
.AddEntityFrameworkStores<MyContext, Guid>()
.AddUserStore<ApplicationUserStore>()
.AddRoleStore<ApplicationRoleStore>()
.AddUserManager<ApplicationUserManager>()
.AddRoleManager<ApplicationRoleManager>()
.AddDefaultTokenProviders();
var builder = new ContainerBuilder();
builder.Populate(services);
var container = builder.Build();
return container.Resolve<IServiceProvider>();
}
Зависимость этого конструктора будет работать:
public AccountController(UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager)
Этого не будет:
public AccountController(ApplicationUserManager userManager, SignInManager<ApplicationUser> signInManager)
У кого-то есть идея о том, что я делаю неправильно?
Ответы
Ответ 1
DI в целом предназначен для разработки с интерфейсом; .AddUserManager<ApplicationUserManager>()
указывает реализацию UserManager<>
, а не интерфейс службы. Это означает, что он все еще ожидает, что вы получите UserManager<ApplicationUser>
и будете использовать его именно так; он даст вам ApplicationUserManager
.
Я предполагаю, что у вас есть дополнительные методы, которые вы хотите использовать на своем ApplicationUserManager
. Если нет, просто используйте конструктор зависимости так, как он работает, и наслаждайтесь развитием интерфейса. Если это так, у вас есть 3 варианта:
-
Использовать расширение с помощью композиции, а не наследования. Вместо того, чтобы наследовать от UserManager<>
, напишите ApplicationUserManager
в качестве класса оболочки; вы можете включить его в конструктор. Это должно предоставить вам все функциональные возможности внутри ApplicationUserManager
.
-
Добавьте его как есть в каркас DI самостоятельно. Это не так сложно, как кажется, поскольку UserManager<>
не имеет реального состояния:
services.AddScoped<ApplicationUserManager>();
Недостаток заключается в том, что у вас фактически есть два объекта UserManager<>
для области пользователя; в результате может быть некоторая неэффективность. Из состояния текущего кода я не думаю, что это так.
-
Запишите его как методы расширения. Если у вас есть несколько зависимостей, а не только базовая функциональность UserManager<>
, это может быть очень сложно.
Ответ 2
Теперь я на ASP.NET Core 1.1, и это поведение было исправлено.
Я могу легко реализовать собственный UserManager и UserStore, а затем загрузите приложение следующим образом:
// identity models
services
.AddIdentity<ApplicationUser, ApplicationRole>()
.AddEntityFrameworkStores<ApplicationDbContext, Guid>()
.AddUserManager<ApplicationUserManager>()
.AddUserStore<ApplicationUserStore>()
.AddDefaultTokenProviders();
и вводить как UserManager, так и UserStore в мой контроллер без каких-либо проблем:
public AccountController(
IIdentityServerInteractionService interaction,
IClientStore clientStore,
IHttpContextAccessor httpContextAccessor,
ApplicationUserManager userManager,
SignInManager<ApplicationUser> signInManager,
IEmailSender emailSender,
ISmsSender smsSender,
ILoggerFactory loggerFactory)
{
_interaction = interaction;
_userManager = userManager;
_signInManager = signInManager;
_emailSender = emailSender;
_smsSender = smsSender;
_logger = loggerFactory.CreateLogger<AccountController>();
_account = new AccountService(_interaction, httpContextAccessor, clientStore);
}