ASP.NET Core 2.x现在将标识页和逻辑隐藏在库中。为了用新属性扩展IdentityUser
实体,并添加UI和逻辑来处理这些新属性,我们现在可以运行"Identity scaffolder"(在MyProject->add->new scaffolded项下)。不幸的是,这些文档充其量是不完整的,而且在很多情况下,完全是错误的。
我正在努力弄清楚如何与架子工和由此产生的代码进行斗争,以实现我认为相当标准的用例:
- 我从一个新的ASP.NET Core MVC应用程序开始
- 我想用我自己的属性来扩展
IdentityUser
。由于这涉及到创建一个继承类,所以我希望新类的名称为ApplicationUser
- 我想搭建我需要处理的身份页面(登录、注册、管理等)
-
我想使用现有的
ApplicationDbContext
我的问题是,在阅读文档和与Identity架子工玩耍时,我不知道如何让架子工让我扩展IdentityUser
并继续使用现有的ApplicationDbContext
。
在查看了文档并与架子工和生成的代码进行了比较之后,我想我已经了解了大部分内容。
- 从一个新的ASP.NET核心Web应用程序开始,使用"个人用户帐户"身份验证。显然,无论您是从"Web应用程序"(即Razor Pages)还是"Web应用(模型-视图-控制器)"(即MVC)开始,都无关紧要。最终,Identity页面将是Razor页面,但它们在MVC应用程序中的功能很好
- 构建解决方案。我不确定这是否有必要,但这并不伤人
- 在继续之前,请确保您喜欢您的数据库连接字符串(在appsettings.json中)。在Package Manager控制台中,输入命令更新数据库。这显然更新了ApplicationDbContextModelSnapshot.cs文件,以包含从项目模板获得的初始迁移。如果跳过这一步,那么在添加第一个迁移时,它将包括00000000000000_CreateIdentitySchema.cs中已有的所有迁移步骤。此外,显然需要这一步才能让架子工识别现有的
ApplicationDbContext
- 右键单击项目并选择添加->新建脚手架项目;选择标识项目类型
- 指定现有的_Layout.cshtml并选择要构建脚手架的页面
- 在数据上下文类旁边,单击下拉箭头并选择现有的
ApplicationDbContext
- 单击"添加"按钮以执行脚手架
此时,您的项目已连接到现有的ApplicationDbContext
和IdentityUser
类。现在,您可以扩展IdentityUser
并连接Identity页面以使用新的扩展实体:
添加从IdentityUser
:继承的新ApplicationUser
类
public class ApplicationUser : IdentityUser
{
public string Nickname { get; set; }
}
将新的ApplicationUser
实体添加到ApplicationDbContext
类:
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<ApplicationUser> AppUsers { get; set; }
}
将<IdentityUser>
的所有实例替换为<ApplicationUser>
。这意味着您将更改startup.cs以调用services.AddDefaultIdentity<ApplicationUser>()
,并替换对SigninManager
和UserManager
的所有引用以指定新的<ApplicationUser>
Type参数。
Whew。。。现在,您可以进入Register.cshtml.cs之类的内容,创建(或获取)一个新的ApplicationUser
而不是IdentityUser
,并且所有管道都将连接到ApplicationUser
。例如,Register.cshtml.cs中的代码可能如下所示:
var user = new ApplicationUser {
UserName = Input.Email,
Email = Input.Email,
Nickname = Input.Nickname // New property
};
var result = await _userManager.CreateAsync(user, Input.Password);
通常,在没有Identity的情况下,ApplicationDbContext
继承自DbContext
。
我有四个项目的解决方案。WEB
、WebAPI
、DATA
和ENTITIES
。
我有一个位于DATA
中的单个ApplicationDbContext
,并已将其修改为继承自IdentityDbContext
,例如:
public class ApplicationDbContext : IdentityDbContext<IdentityUser>
现在,ENTITIES
是定义模型(POCO)的地方。
并且,DATA
中的AppliationDbContext
包含对这些类的引用,并包含EF使用的DbSet<T>
属性设置器。ENTITIES
中的Person
(又名ApplicationUser
)类如下所示:
public class Person : IdentityUser
{
[PersonalData]
public string LastName { get; set; }
在WEB
项目中,有了对DATA
和ApplicationDContext
的适当引用,我只有一个services.AddDbContext<T>
依赖引用;则在CCD_ 47服务添加中使用该上下文
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<IdentityUser>()
.AddEntityFrameworkStores<ApplicationDbContext>();
这似乎达到了只使用一个DbContext
服务的目的。它还扩展了AspNetUsers
表,以包括我在位于ENTITIES
内的POCOPerson
模型类中设置的[PersonalData]
属性。
现在,自从<IdentityUser>
已经扩展,在我的情况下是Person
,所有对IdentityUser
的引用都应该更新以反映这一点。所以Startup.ConfigureServices
现在看起来是这样的:
services.AddDefaultIdentity<Person>()
.AddEntityFrameworkStores<ApplicationDbContext>();
而且,在UI中,为了访问"Person"添加的属性,~/Identity/Account/Manage/Index.cshtml.cs
中的引用也需要更新:
private readonly UserManager<Person> _userManager;
private readonly SignInManager<Person> _signInManager;
private readonly IEmailSender _emailSender;
public IndexModel(
UserManager<Person> userManager,
SignInManager<Person> signInManager,
IEmailSender emailSender)
{
_userManager = userManager;
_signInManager = signInManager;
_emailSender = emailSender;
}
您必须更新index.cshtml.cs
中的"InputModel"以及OnGetAsync()
方法中的"new up"来映射属性——类似于默认设置处理Email
的方式。
最后,还有index.cshtml
视图文件,用于访问UI/Rarzor显示。
这应该会让你开始你的问题中的项目1-4。
尝试右键单击解决方案,但无法选择ApplicationDbContext。我不得不将Visual Studio更新到最新版本,并安装所有最新的SDK(.Net Core 3.1)。之后,一切都很顺利。希望它能帮助到别人。