在处理大量数据的应用中,使用字符串作为用户ID可能会导致检索信息时的性能问题。因此,将主键类型更改为整数是一个更好的解决方案。ASP.NET Identity框架2.0引入了一些新特性,其中包括通用的主键类型,使得可以自定义主键类型。Identity框架2.0包含在Visual Studio 2013更新2中(2014年5月12日发布)。
本文将通过以下步骤展示如何将主键数据类型从字符串更改为整数:
使用Visual Studio 2013更新2创建一个新的ASP.NET Web应用程序,命名为Identity2IntPK,并选择MVC模板和Individual User Account选项。Visual Studio 2013的MVC模板会创建如下结构:
需要修改以下文件以完成此任务:
1. IdentityModels.cs:
打开文件并添加UserRoleIntPk、UserClaimIntPk、UserLoginIntPk、RoleIntPk、UserStoreIntPk、RoleStoreIntPk类。
public class UserRoleIntPk : IdentityUserRole<int>
{
}
public class UserClaimIntPk : IdentityUserClaim<int>
{
}
public class UserLoginIntPk : IdentityUserLogin<int>
{
}
public class RoleIntPk : IdentityRole<int, UserRoleIntPk>
{
public RoleIntPk() { }
public RoleIntPk(string name) { Name = name; }
}
public class UserStoreIntPk : UserStore<ApplicationUser, RoleIntPk, int, UserLoginIntPk, UserRoleIntPk, UserClaimIntPk>
{
public UserStoreIntPk(ApplicationDbContext context) : base(context)
{
}
}
public class RoleStoreIntPk : RoleStore<RoleIntPk, int, UserRoleIntPk>
{
public RoleStoreIntPk(ApplicationDbContext context) : base(context)
{
}
}
同时更改ApplicationUser和ApplicationDbContext类。
public class ApplicationUser : IdentityUser<int, UserLoginIntPk, UserRoleIntPk, UserClaimIntPk>
{
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(ApplicationUserManager manager)
{
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// 添加自定义用户声明
return userIdentity;
}
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, RoleIntPk, int, UserLoginIntPk, UserRoleIntPk, UserClaimIntPk>
{
public ApplicationDbContext() : base("DefaultConnection")
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
2. IdentityConfig.cs:
打开App_Start文件夹中的此文件并更改ApplicationUserManager类。更改后的ApplicationUserManager将如下所示:
public class ApplicationUserManager : UserManager<ApplicationUser, int>
{
public ApplicationUserManager(IUserStore<ApplicationUser, int> store) : base(store)
{
}
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
var manager = new ApplicationUserManager(new UserStoreIntPk(context.Get<ApplicationDbContext>()));
// 配置用户名验证逻辑
manager.UserValidator = new UserValidator<ApplicationUser, int>(manager)
{
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = true
};
// 配置密码验证逻辑
manager.PasswordValidator = new PasswordValidator
{
RequiredLength = 6,
RequireNonLetterOrDigit = true,
RequireDigit = true,
RequireLowercase = true,
RequireUppercase = true,
};
manager.RegisterTwoFactorProvider("PhoneCode", new PhoneNumberTokenProvider<ApplicationUser, int>
{
MessageFormat = "Your security code is: {0}"
});
manager.RegisterTwoFactorProvider("EmailCode", new EmailTokenProvider<ApplicationUser, int>
{
Subject = "Security Code",
BodyFormat = "Your security code is: {0}"
});
manager.EmailService = new EmailService();
manager.SmsService = new SmsService();
var dataProtectionProvider = options.DataProtectionProvider;
if (dataProtectionProvider != null)
{
manager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser, int>(dataProtectionProvider.Create("ASP.NET Identity"));
}
return manager;
}
}
3. Startup.Auth.cs:
打开App_Start文件夹中的此文件并用新代码替换旧代码。
// 旧代码
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
// 新代码
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser, int>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateCallback: (manager, user) => user.GenerateUserIdentityAsync(manager),
getUserIdCallback: (id) => (Int32.Parse(id.GetUserId()))
)
工作几乎完成了。如果编译代码,会得到大约16个错误,所有错误都在AccountController.cs文件中。因此,需要更改此文件以适应新系统。
打开AccountController.cs文件,并将所有userId类型从字符串更改为整数。然后替换所有User.Identity.GetUserId()为int.Parse(User.Identity.GetUserId()),除了LinkLogin函数。
同时,将LinkLoginCallback更改为:
// GET: /Account/LinkLoginCallback
public async Task LinkLoginCallback()
{
var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync(XsrfKey, User.Identity.GetUserId());
if (loginInfo == null)
{
return RedirectToAction("Manage", new { Message = ManageMessageId.Error });
}
IdentityResult result = await UserManager.AddLoginAsync(int.Parse(User.Identity.GetUserId()), loginInfo.Login);
if (result.Succeeded)
{
return RedirectToAction("Manage");
}
return RedirectToAction("Manage", new { Message = ManageMessageId.Error });
}
现在编译项目,如果一切顺利,然后运行它。点击导航菜单中的注册并添加一个用户。
Entity Framework将为创建一个数据库,包含AspNet授权表。如果想检查数据库中发生了什么,那么打开服务器资源管理器中的DefaultConnection。右键单击AspNetUsers表并选择打开表定义,将看到ID现在是整数而不是字符串。