我正在将 .Net Framework 4.7.2 mvc 网站升级到 ASP.NET Core (.Net8)。旧站点使用EntityFramework 6.4和Microsoft.AspNet.Identity.Core 2.2。新站点使用 EntityFrameworkCore 8.0 和 Microsoft.AspNetCore.Identity.EntityFramework 8.0。
现有数据库包含早期身份框架中的表。表名和列几乎相同:
IdentityRole, IdentityUser, IdentityUserClaim, IdentityUserLogin, IdentityUserRole
。但是,IdentityUser
不包含新的 ConcurrencyStamp
字段,同时还包含自定义字段 LastLoginTime
。
我对数据库进行了逆向工程以创建新的实体框架模型,并且我认为我已经正确确定我应该不使用生成的
Identity...
类,因为这些似乎是由身份框架提供的(对吗?)
因此剩下两个需求:
LastLoginTime
字段阅读诸如(使用 ASP.NET Identity 时如何更改表名称?)之类的答案表明我应该能够简单地从
.ToTable("IdentityUser")
调用 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
}
}
程序.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();
}
当我测试我的控制器时,我看到:
MySql.Data.MySqlClient.MySqlException (0x80004005): Table 'MyDb.AspNetUsers' doesn't exist
[...omitted]
at Microsoft.AspNetCore.Identity.UserManager`1.FindByNameAsync(String userName)
为什么
FindByNameAsync
搜索AspNetUsers
而不是我通过ToTable("IdentityUser")
指定的表?
您的
ApplicationDbContext
应源自 ApplicationUser
;不是IdentityUser
ApplicationDbContext : IdentityDbContext<IdentityUser>
应该是
ApplicationDbContext : IdentityDbContext<ApplicationUser>