Я в настоящее время ходит вокруг с Беном Фостерсом Saaskit.Почему AppTenant null только при посеве данных?
я продлил ApplicationUser
со свойством AppTenantId и создал пользовательское UserStore, который использует AppTenant для идентификации пользователя:
public class TenantEnabledUserStore : IUserStore<ApplicationUser>, IUserLoginStore<ApplicationUser>,
IUserPasswordStore<ApplicationUser>, IUserSecurityStampStore<ApplicationUser>
{
private bool _disposed;
private AppTenant _tenant;
private readonly ApplicationDbContext _context;
public TenantEnabledUserStore(ApplicationDbContext context, AppTenant tenant)
{
_context = context;
_tenant = tenant;
}
/*... implementation omitted for brevity*/
}
Если пользователь регистрируется или входит в, это работает отлично. Правильно установлен AppTenant
. Проблема возникает, когда SeedData.Initialize(app.ApplicationServices);
вызывается в конце моего Statup.Configure()
метода:
public static class SeedData
{
public async static void Initialize(IServiceProvider provider)
{
using (var context = new ApplicationDbContext(
provider.GetRequiredService<DbContextOptions<ApplicationDbContext>>()))
{
var admin = new ApplicationUser
{
AppTenantId = 1,
Email = "[email protected]",
UserName = "Administrator",
EmailConfirmed = true
};
if(!context.Users.Any(u => u.Email == admin.Email))
{
var userManager = provider.GetRequiredService<UserManager<ApplicationUser>>();
await userManager.CreateAsync(admin, "Penis123#");
}
context.SaveChanges();
}
}
}
usermanager это звонит пользовательский userstore, но теперь AppTenant равна нулю. Когда код, наконец, достигает
public Task<ApplicationUser> FindByNameAsync(string normalizedUserName, CancellationToken cancellationToken)
{
return _context.Users.FirstOrDefaultAsync(u => u.NormalizedUserName == normalizedUserName && u.AppTenantId == _tenant.AppTenantId, cancellationToken);
}
Я столкнулся с System.InvalidoperationException
, потому что AppTenant передается как нуль в конструкторе упомянутой выше userstore.
Что я делаю неправильно? Я посеял неправильный путь или я забыл что-то фундаментальное здесь?
Update: Сейчас я взял лом-подход, избегал usermanager и создал свой собственный экземпляр userstore с макетом AppTenant:
if (!context.Users.Any(u => u.Email == admin.Email))
{
var userStore = new TenantEnabledUserStore(context, new AppTenant
{
AppTenantId = 1
});
await userStore.SetPasswordHashAsync(admin, new PasswordHasher<ApplicationUser>().HashPassword(admin, "VeryStrongPassword123#"), default(CancellationToken));
await userStore.SetSecurityStampAsync(admin, Guid.NewGuid().ToString("D"), default(CancellationToken));
await userStore.CreateAsync(admin, default(CancellationToken));
}
Nontheless, я по-прежнему заинтересован в более чистый подход, который не чувствует себя взломанным.
является частью арендатора данных для посева? т. е. произойдет ли посев для первого арендатора? –
Это не сработает. в этом примере вы создаете экземпляр 'ApplicationDbContext' вручную, используя ключевое слово' new'. Но в следующей строке вы разрешаете 'UserManager', который зависит от 'ApplicationDbContext'. Управляемый пользователь получит другой экземпляр 'ApplicationDbContext', где' user' еще не создан (поскольку метод 'SaveChanges' вызывается после' CreateAsync' –
Tseng
Вам нужно также разрешить ваш''ApplicationDbContext' из контейнера IoC , но будьте осторожны. Когда вы делаете это во время запуска с помощью приложения.ApplicationServices вы создаете singleton (во время загрузки приложения нет запроса). Сначала вам нужно создать область действия, затем устранить ее из области действия и ограничить область действия в конце. – Tseng