I just migrated from ASP.NET MVC to Blazor. I have created a new project that has authorization and authentication. When I want to add a series of new columns to the AspNetUsers
table, I frequently encounter various errors.
IdentityUser Issue - Cannot create a DbSet for 'IdentityUser' this type is not included in the model for the context
and
Unable to materialize entity instance of type 'Resource'. No discriminators matched the discriminator value ''."
and
Cannot create a DbSet for 'IdentityUser' because this type is not included in the model for the context
and
The entity type 'IdentityUserLogin' requires a primary key to be defined
My DbContext looks like this:
using LoginAndAuthProj.Server.Entities;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.InMemory.ValueGeneration.Internal;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.ValueGeneration.Internal;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace LoginAndAuthProj.Server.MainDbContext
{
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<MyEventUserLog>(entity =>
{
var pb = entity.Property(e => e.UId).ValueGeneratedOnAdd();
if (Database.IsInMemory())
{
pb.HasValueGenerator<InMemoryIntegerValueGenerator<decimal>>();
}
});
base.OnModelCreating(modelBuilder);
}
public DbSet<MyEventUserLog> MyEventUserLogs { get; set; }
}
}
And the login controller:
using LoginAndAuthProj.Shared.DTOs;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
namespace LoginAndAuthProj.Server.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class AccountController : ControllerBase
{
private readonly UserManager<IdentityUser> _userManager;
private readonly SignInManager<IdentityUser> _signInManager;
private readonly IConfiguration _configuration;
public AccountController(UserManager<IdentityUser> userManager, SignInManager<IdentityUser> signInManager,
IConfiguration configuration)
{
_userManager = userManager;
_signInManager = signInManager;
_configuration = configuration;
}
[HttpPost("Login")]
public async Task<ActionResult<UserToken>> Login([FromBody] UserInfo userInfo)
{
var result = await _signInManager
.PasswordSignInAsync(userInfo.Email, userInfo.StrPassword, false, false);
UserToken ut = new UserToken();
// if(result.RequiresTwoFactor == )
if (result.Succeeded)
{
ut = BuildToken(userInfo);
ut.Responser.ResponsState = Shared.Enumes.ResponserState.Successful;
ut.Responser.StrMessage = "Login OK . . .";
return ut;
}
else
{
if (result.RequiresTwoFactor)
{
var user = await _userManager.FindByEmailAsync(userInfo.Email);
var tokenMain = await _userManager.GenerateTwoFactorTokenAsync(user, "Email");
ut.Responser.StrMessage = tokenMain.ToString();
ut.Responser.ResponsState = Shared.Enumes.ResponserState.TwoVerification;
Console.WriteLine(ut.Responser.StrMessage);
return ut;
}
else
{
ut.Responser.ResponsState = Shared.Enumes.ResponserState.Fail;
ut.Responser.StrMessage = "Login OK . . .";
//return BadRequest("Login Failed");
return ut;
}
}
}
[HttpPost("LoginTwoStep")]
public async Task<ActionResult<UserToken>> LoginTwoStep([FromBody] UserInfo userInfo)
{
try
{
var appUser = await _userManager.FindByEmailAsync(userInfo.Email);
var result = await _signInManager.TwoFactorSignInAsync("Email", userInfo.StrCode, false, userInfo.CanRememberMe);
if (result.Succeeded)
{
return BuildToken(userInfo);
}
else
{
UserToken ut = new UserToken();
ut.Responser.ResponsState = Shared.Enumes.ResponserState.Fail;
ut.Responser.StrMessage = "Code is wrong . . . .";
return ut;
}
}
catch (Exception ex)
{
String Err = ex.Message;
Console.WriteLine(Err);
UserToken ut = new UserToken();
ut.Responser.ResponsState = Shared.Enumes.ResponserState.Fail;
ut.Responser.StrMessage = "Code is wrong . . . ." Err;
return ut;
}
}
[HttpPost("Create")]
public async Task<ActionResult<UserToken>> CreateUser([FromBody] UserInfo model)
{
var user = new IdentityUser { UserName = model.Email, Email = model.Email, PhoneNumber = "00000011110000",
EmailConfirmed = true, PhoneNumberConfirmed = true, TwoFactorEnabled = false, LockoutEnabled = false, AccessFailedCount = 0};
try
{
var result = await _userManager.CreateAsync(user, model.StrPassword);
if (result.Succeeded)
{
return BuildToken(model);
}
else
{
return BadRequest("Username Or Password is invalid");
}
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
private UserToken BuildToken(UserInfo userInfo)
{
var claims = new List<Claim>()
{
new Claim(ClaimTypes.Name, userInfo.Email),
new Claim(ClaimTypes.Email, userInfo.Email),
new Claim("MyClaim", "My Claim Value")
};
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["jwt:key"]));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var expireDate = DateTime.Now.AddDays(30);
JwtSecurityToken token = new JwtSecurityToken(
issuer: null,
audience: null,
claims: claims,
expires: expireDate,
signingCredentials: creds
);
return new UserToken
{
Token = new JwtSecurityTokenHandler().WriteToken(token),
ExpireDate = expireDate
};
}
}
}
Startup file in Server Layer
using LoginAndAuthProj.Server.MainDbContext;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.ResponseCompression;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using System;
using Microsoft.IdentityModel.Tokens;
using System.Text;
using Newtonsoft.Json;
using LoginAndAuthProj.Shared.DTOs;
namespace LoginAndAuthProj.Server
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))
);
services.AddControllersWithViews();
services.AddRazorPages();
services.AddIdentity<IdentityUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["jwt:key"])),
ClockSkew = TimeSpan.Zero
};
});
services.AddMvc().AddNewtonsoftJson(options => options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore);
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseWebAssemblyDebugging();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseBlazorFrameworkFiles();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapControllers();
endpoints.MapFallbackToFile("index.html");
});
}
}
}
I want to add just this three fields to that table
public String UsersAddress { get; set; }
public int CityID { get; set; }
public Byte[] PictureOfUser { get; set; }
CodePudding user response:
Referring to this video from youtube website! at first you shoud create a class and add you fields into that class:
public class ApplicationUser : IdentityUser
{
[MaxLength(1500, ErrorMessage = "The Error Message")]
public String UsersAddress { get; set; }
public int? CityID { get; set; }
public Byte[]? PictureOfUser { get; set; }
}
Then change ApplicationDbContext
to IdentityDbContext<ApplicationUser>
something like below:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<MyEventUserLog>(entity =>
{
var pb = entity.Property(e => e.UId).ValueGeneratedOnAdd();
if (Database.IsInMemory())
{
pb.HasValueGenerator<InMemoryIntegerValueGenerator<decimal>>();
}
});
base.OnModelCreating(modelBuilder);
}
public DbSet<MyEventUserLog> MyEventUserLogs { get; set; }
}
After that in Startup file chanage this part
services.AddIdentity<IdentityUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
to
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
and inside of login controller replace IdentityUser
with ApplicationUser
then use Enable-migration
after that add-migration WithName
finally Update-Databse
and run the project.