I’m upgrading a .Net Framework 4.7.2 mvc website to ASP.NET Core (.Net8). The old site used EntityFramework 6.4 and Microsoft.AspNet.Identity.Core 2.2. The new site uses EntityFrameworkCore 8.0 and Microsoft.AspNetCore.Identity.EntityFramework 8.0.
There is an existing database with tables from the earlier Identity framework. The table names and columns are nearly identical: IdentityRole, IdentityUser, IdentityUserClaim, IdentityUserLogin, IdentityUserRole
. However, IdentityUser
does not contain the new ConcurrencyStamp
field, while also containing a custom field LastLoginTime
.
I scaffold reversed-engineered the DB to create new Entity Framework models, and I think I’ve correctly determined I should not use the generated Identity...
classes, as these seem to be provided by the identity framework (right?)
So that leaves two needs:
- Customize IdentityUser to include the custom
LastLoginTime
field - Ensure default Identity- classes are mapped to existing table names.
Reading answers such as (How can I change the table names when using ASP.NET Identity?) suggests I should be able to simply call .ToTable("IdentityUser")
from OnModelCreating(ModelBuilder modelBuilder)
.
ApplicationDbContext.cs
public partial class ApplicationDbContext : IdentityDbContext<IdentityUser> {
public ApplicationDbContext(DbContextOptions options) : base(options) {}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<ApplicationUser>(entity =>
{
entity.ToTable("IdentityUser");
entity.Property(e => e.LastLoginTime).HasColumnType("datetime");
entity.Property(e => e.LockoutEnd).HasColumnName("LockoutEndDateUtc").HasColumnType("datetime)");
});
}
ApplicationUser.cs
public class ApplicationUser : IdentityUser
{
public DateTime? LastLoginTime { get; set; }
public ApplicationUser()
: base() { }
public ApplicationUser(string userName)
: base(userName) {}
}
HomeController.cs
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly UserManager<ApplicationUser> _userManager;
public HomeController(ILogger<HomeController> logger, SignInManager<ApplicationUser> signInManager, UserManager<ApplicationUser> userManager)
{
_logger = logger;
_signInManager = signInManager;
_userManager = userManager;
}
public async Task<ActionResult> Login(LoginViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
var identityUser = await _signInManager.UserManager.FindByNameAsync(model.UserName);
// EXCEPTION
}
}
Program.cs
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews().AddRazorRuntimeCompilation();
builder.Services.AddMvcCore().AddJsonOptions(o =>
{
o.JsonSerializerOptions.PropertyNamingPolicy = null;
o.JsonSerializerOptions.DictionaryKeyPolicy = null;
});
builder.Services.AddDistributedMemoryCache();
builder.Services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromMinutes(5);
options.Cookie.HttpOnly = true;
options.Cookie.IsEssential = true;
});
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseMySQL(builder.Configuration.GetConnectionString("Default") ?? ""));
builder.Services.AddIdentity<ApplicationUser, IdentityRole>(options =>
{
options.Password.RequiredLength = 8;
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
options.Lockout.MaxFailedAccessAttempts = 5;
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
builder.Services.AddHttpContextAccessor();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseSession();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
AppDomain.CurrentDomain.SetData("ContentRootPath", builder.Environment.ContentRootPath);
AppDomain.CurrentDomain.SetData("WebRootPath", builder.Environment.WebRootPath);
app.Run();
}
When I test my controller, I see:
MySql.Data.MySqlClient.MySqlException (0x80004005): Table 'MyDb.AspNetUsers' doesn't exist
[...omitted]
at Microsoft.AspNetCore.Identity.UserManager`1.FindByNameAsync(String userName)
Why is FindByNameAsync
searching AspNetUsers
instead of the table I specified via ToTable("IdentityUser")
?
Peter S is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.