现有EF Database First的ASP.NET Web API项目添加Identity Framework报错如何解决
问题根因
核心错误由两个原因导致:
- Identity Framework 底层依赖 Code First 模式来生成、操作身份验证相关表(AspNetUsers、AspNetRoles 等),但你当前的
atishEntities是 Database First 生成的上下文,OnModelCreating方法里直接抛出UnintentionalCodeFirstException阻断了 Identity 的模型配置逻辑,且 Database First 模式的 EDMX 上下文本身就不支持 Code First 的模型构建、迁移操作。 - 注册按钮的逻辑完全没有用到之前配置的 OWIN 托管的
AppUserManager,直接实例化无参UserStore会默认读取DefaultConnection连接字符串,和现有配置完全脱节。
解决方案
推荐采用拆分上下文的方案,侵入性低、后续维护成本低:
方案1:拆分上下文(推荐)
不要混合业务的 Database First 上下文和 Identity 的 Code First 上下文,两个上下文操作同一个数据库即可:
步骤1:回滚原有上下文修改
把之前改的atishEntities继承关系恢复成原来继承DbContext的状态,不要修改自动生成的 Database First 上下文代码,避免后续更新 EDMX 时自定义代码被覆盖。
步骤2:新增 Identity 专用 Code First 上下文
新建独立的 Identity 上下文类:
using Microsoft.AspNet.Identity.EntityFramework; using System.Data.Entity; namespace EmployeeService { public class AppIdentityDbContext : IdentityDbContext<IdentityUser> { public AppIdentityDbContext() : base("name=IdentityConnection") { } public static AppIdentityDbContext Create() { return new AppIdentityDbContext(); } } }
步骤3:新增 Identity 专用连接字符串
在 web.config 的<connectionStrings>节点添加纯 SQLClient 类型的连接字符串,指向同一个 atish 数据库:
<add name="IdentityConnection" connectionString="data source=.;initial catalog=atish;integrated security=True;MultipleActiveResultSets=True;" providerName="System.Data.SqlClient" />
步骤4:调整 AppUserManager 和 Startup 配置
修改 AppUserManager 的 Create 方法,绑定新的 Identity 上下文:
public static AppUserManager Create(IdentityFactoryOptions<AppUserManager> options, IOwinContext context) { var manager = new AppUserManager( new UserStore<IdentityUser>(context.Get<AppIdentityDbContext>())); return manager; }
修改 Startup 类的上下文注册逻辑:
public void Configuration(IAppBuilder app) { app.CreatePerOwinContext(AppIdentityDbContext.Create); app.CreatePerOwinContext<AppUserManager>(AppUserManager.Create); // 其余原有Cookie配置保持不变 }
步骤5:修复注册按钮逻辑
从 OWIN 上下文获取已经配置好的 AppUserManager,不要自行实例化 UserStore:
protected void CreateUser_Click(object sender, EventArgs e) { var manager = Context.GetOwinContext().GetUserManager<AppUserManager>(); var user = new IdentityUser() { UserName = UserName.Text }; IdentityResult result = manager.Create(user, Password.Text); if (result.Succeeded) { StatusMessage.Text = string.Format("用户 {0} 创建成功!", user.UserName); } else { StatusMessage.Text = result.Errors.FirstOrDefault(); } }
步骤6:生成 Identity 相关表
在 Visual Studio 包管理器控制台执行以下命令,在 atish 数据库生成身份验证所需的表:
Enable-Migrations -ContextTypeName EmployeeService.AppIdentityDbContext -MigrationsDirectory Migrations\Identity Add-Migration -ConfigurationTypeName EmployeeService.Migrations.Identity.Configuration InitialIdentity Update-Database -ConfigurationTypeName EmployeeService.Migrations.Identity.Configuration
配置完成后,原有 Employee 业务逻辑走原来的 Database First 上下文,身份验证逻辑走独立的 Identity 上下文,互不影响。
方案2:合并上下文(不推荐)
如果一定要使用同一个上下文,需要手动修改自动生成的atishEntities代码:
- 删掉
OnModelCreating方法里的throw new UnintentionalCodeFirstException();,添加base.OnModelCreating(modelBuilder);调用 Identity 的模型配置逻辑 - 把上下文构造函数绑定的连接字符串改成纯 SQLClient 类型,不要用带 metadata 的 EntityClient 连接字符串
- 后续每次更新 EDMX 都需要手动恢复上述修改,维护成本极高。
内容的提问来源于stack exchange,提问作者atish
相关产品推荐
相关产品推荐

