Reputation: 466
I have a framework which uses the following user type:
public class ApplicationUser : IdentityUser
{
public string WizardState {
get;
set;
}
}
The initial ConfigureService of the startup.cs with the following statement:
services.AddDefaultIdentity<IdentityUser>()
.AddDefaultUI(UIFramework.Bootstrap4)
.AddEntityFrameworkStores<ApplicationDbContext>();
The Index page (index.cshtml) run and prompts to a specific controller/action:
<a href="@Url.Action("Step1","Sample1")" class="btn btn-success btn-lg btn-block">
Start Sample1
The specific controller/action is:
public class Sample1Controller : WizardBaseController
{
public Sample1Controller(IConfiguration configuration,
IWizardNavigatorService<WizardStep> navigatorPersistenceService) :
base(configuration, navigatorPersistenceService)
{
}
public IActionResult Step1()
{
return StepResult(new Step1ViewModel());
}
Where WizardBaseController
derives from Controller
:
public abstract class WizardBaseController : Controller
{
...
}
When clicked to run such page I have the error:
InvalidOperationException: Unable to resolve service for type 'Microsoft.AspNetCore.Identity.UserManager`1[Nexum.Models.ApplicationUser]' while attempting to activate 'Nexum.Services.NavigatorPersistenceService'.
A fact is that it doesn't even run the call controller/action, as in debugging a breakpoint is inserted in the very beginning of it and it doesn't reach that point at all
Then I tried changing the IdentityUser
in the startup.cs to ApplicationUser
as:
services.AddDefaultIdentity<ApplicationUser>()
.AddDefaultUI(UIFramework.Bootstrap4)
.AddEntityFrameworkStores<ApplicationDbContext>();
And then, from just starting the application there was the error:
InvalidOperationException: No service for type 'Microsoft.AspNetCore.Identity.UserManager`1[Microsoft.AspNetCore.Identity.IdentityUser]' has been registered.
Now referring to IdentityUser...
The ApplicationDbContext is this:
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{ }
public DbSet<AreaAtuacao> AreasAtuacao { get; set; }
public DbSet<Criador> Criadores { get; set; }
public DbSet<Estado> Estados { get; set; }
public DbSet<DiscrecaoCliente> DiscrecoesClientes { get; set; }
public DbSet<Empreendedor> Empreendedores { get; set; }
public DbSet<FaixaInvestimento> FaixasInvestimento { get; set; }
public DbSet<Fornecedor> Fornecedores { get; set; }
public DbSet<Investidor> Investidores { get; set; }
public DbSet<Pessoa> Pessoas { get; set; }
public DbSet<RedeSocial> RedesSociais { get; set; }
public DbSet<Servico> Servicos { get; set; }
public DbSet<StartUp> StartUps { get; set; }
public DbSet<Socio> Socios { get; set; }
}
}
I'm completely lost in this...
Upvotes: 0
Views: 3004
Reputation: 264
I'm no expert in this matter but I suspect that if you call AddDefaultIdentity
with IdentityUser
as type parameter, it will register UserManager<IdentityUser>
, same happens if you call it with your user type. So you can't get UserManager
with 2 different type parameters because they are completely different types.
So you should either user one type of user and store their unique properties in some other table or do something hacky like this:
Let's suppose we have these 2 user types with unique properties:
public class User1 : IdentityUser
{
public string UniqueStringProp { get; set; }
}
public class User2 : IdentityUser
{
public int UniqueIntProp { get; set; }
}
In this case you call AddDefaultIdentity with the type parameter IdentityUser. You'll have a UserManager available.
In your DbContext you should write this in your OnModelCreating method:
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<User1>()
.HasBaseType<IdentityUser>();
builder.Entity<User2>()
.HasBaseType<IdentityUser>();
base.OnModelCreating(builder);
}
This way you are telling EntityFramework that User1
and User2
are also subtypes of IdentityUser
and it will put them into the same table (by default).
It will generate a table like this, which will have all the IdentityUser descendants:
You can create users with the UserManager<IdentityUser>
with your unique user type, since the methods require an IdentityUser
, User1
and User2
are also IdentityUsers. However when you need to access the unique data of the users you need to type-check every time, because the query methods will only give you your users as IdentityUser
. So if you wanted to access your User1
's stringProp you'd have to do like this:
var user = await userManager.FindByNameAsync("user1's username");
if (user is User1 user1)
{
// Access user1's string property here
}
Upvotes: 2