asp.net-mvc 如何更改 Microsoft.AspNet.Identity.EntityFramework.IdentityUser 中的 id 类型
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19553424/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to change type of id in Microsoft.AspNet.Identity.EntityFramework.IdentityUser
提问by BenjiFB
(ASP.NET MVC 5, EF6, VS2013)
(ASP.NET MVC 5、EF6、VS2013)
I'm trying to figure out how to change the type of the "Id" field from string to intin the type:
我想弄清楚如何在类型中将“Id”字段的类型从字符串更改为 int:
Microsoft.AspNet.Identity.EntityFramework.IdentityUser
in order to have new user accounts be associated with an integer ID rather than a GUID. But it seems like this will be more complicated than simply adding a new Id property with type int in my derived user class. Take a look at this method signature:
为了让新用户帐户与整数 ID 而不是 GUID 相关联。但这似乎比在我的派生用户类中简单地添加一个 int 类型的新 Id 属性要复杂得多。看看这个方法签名:
(from Assembly Microsoft.AspNet.Identity.Core.dll)
(来自 Assembly Microsoft.AspNet.Identity.Core.dll)
public class UserManager<TUser> : IDisposable where TUser : global::Microsoft.AspNet.Identity.IUser
{
...
public virtual Task<IdentityResult> AddLoginAsync(string userId, UserLoginInfo login);
...
}
So it seems that there are other methods baked into the ASP.NET identity framework which require the userId to be a string. Would I need to reimplement these classes as well?
因此,ASP.NET 标识框架中似乎还有其他方法需要 userId 为字符串。我还需要重新实现这些类吗?
An explanation of why I don't want to store GUIDs for ids in the user table:
解释为什么我不想在用户表中存储 id 的 GUID:
-There will be other tables that relate data to the users table via a foreign key. (When users save content on the site.) I see no reason to use the larger field type and spend extra database space with no clear advantages. (I know that there are other posts about using GUIDs vs int ids, but it seems like many suggest that int ids are faster and use less space, which still leaves me wondering.)
- 将有其他表通过外键将数据与用户表相关联。(当用户在网站上保存内容时。)我认为没有理由使用更大的字段类型并花费额外的数据库空间而没有明显的优势。(我知道还有其他关于使用 GUID 与 int id 的帖子,但似乎很多人都认为 int id 更快且使用更少的空间,这仍然让我想知道。)
-I plan to expose a restful endpoint to allow users to retrieve data about a particular user. I think:
- 我计划公开一个宁静的端点,以允许用户检索有关特定用户的数据。我认为:
/users/123/name
is cleaner than
比
/users/{af54c891-69ba-4ddf-8cb6-00d368e58d77}/name
Does anyone know why the ASP.NET team decided to implement IDs this way? Am I being short sighted in trying to change this to an int type? (Perhaps there are benefits I'm missing.)
有谁知道为什么 ASP.NET 团队决定以这种方式实现 ID?我是否在尝试将其更改为 int 类型时目光短浅?(也许我缺少一些好处。)
Thanks...
谢谢...
-Ben
-本
采纳答案by Hao Kung
So if you want int ids, you need to create your own POCO IUser class and implement your IUserStore for your custom IUser class in the 1.0 RTM release.
因此,如果您需要 int id,则需要创建您自己的 POCO IUser 类并在 1.0 RTM 版本中为您的自定义 IUser 类实现您的 IUserStore。
This is something we didn't have time to support, but I'm looking into making this easy(ier) in 1.1 right now. Hopefully something will be available in the nightly builds soon.
这是我们没有时间支持的事情,但我现在正在考虑在 1.1 中使它变得更容易(更)。希望很快就会在每晚构建中提供一些东西。
Updated with 1.1-alpha1 example:How to get nightly builts
更新了 1.1-alpha1 示例:如何获得夜间构建
If you update to the latest nightly bits, you can try out the new 1.1-alpha1 apis which should make this easier now: Here's what plugging in Guids instead of strings should look like for example
如果您更新到最新的夜间位,您可以尝试新的 1.1-alpha1 apis,这现在应该会更容易:以下是插入 Guids 而不是字符串的样子,例如
public class GuidRole : IdentityRole<Guid, GuidUserRole> {
public GuidRole() {
Id = Guid.NewGuid();
}
public GuidRole(string name) : this() { Name = name; }
}
public class GuidUserRole : IdentityUserRole<Guid> { }
public class GuidUserClaim : IdentityUserClaim<Guid> { }
public class GuidUserLogin : IdentityUserLogin<Guid> { }
public class GuidUser : IdentityUser<Guid, GuidUserLogin, GuidUserRole, GuidUserClaim> {
public GuidUser() {
Id = Guid.NewGuid();
}
public GuidUser(string name) : this() { UserName = name; }
}
private class GuidUserContext : IdentityDbContext<GuidUser, GuidRole, Guid, GuidUserLogin, GuidUserRole, GuidUserClaim> { }
private class GuidUserStore : UserStore<GuidUser, GuidRole, Guid, GuidUserLogin, GuidUserRole, GuidUserClaim> {
public GuidUserStore(DbContext context)
: base(context) {
}
}
private class GuidRoleStore : RoleStore<GuidRole, Guid, GuidUserRole> {
public GuidRoleStore(DbContext context)
: base(context) {
}
}
[TestMethod]
public async Task CustomUserGuidKeyTest() {
var manager = new UserManager<GuidUser, Guid>(new GuidUserStore(new GuidUserContext()));
GuidUser[] users = {
new GuidUser() { UserName = "test" },
new GuidUser() { UserName = "test1" },
new GuidUser() { UserName = "test2" },
new GuidUser() { UserName = "test3" }
};
foreach (var user in users) {
UnitTestHelper.IsSuccess(await manager.CreateAsync(user));
}
foreach (var user in users) {
var u = await manager.FindByIdAsync(user.Id);
Assert.IsNotNull(u);
Assert.AreEqual(u.UserName, user.UserName);
}
}
回答by krzychu
Using a Stefan Cebulak's answer and a Ben Foster's great blog article ASP.NET Identity Stripped BareI have came up with below solution, which I have applied to ASP.NET Identity 2.0with a generated by Visual Studio 2013 AccountController.
使用Stefan Cebulak的回答和 Ben Foster 的精彩博客文章ASP.NET Identity Stripped Bare我想出了以下解决方案,我已将其应用于 ASP.NET Identity 2.0并使用 Visual Studio 2013 生成AccountController。
The solution uses an integer as a primary key for users and also allows to get an ID of currently logged in user without making a trip to the database.
该解决方案使用整数作为用户的主键,并且还允许获取当前登录用户的 ID,而无需访问数据库。
Here are the steps, you need to follow:
以下是您需要遵循的步骤:
1. Create custom user-related classes
1.创建自定义用户相关类
By default, the AccountControlleruses classes, which are using string, as a type of a primary key. We need to create below classes, which will use an intinstead. I have defined all below classes in one file: AppUser.cs
默认情况下,AccountController使用类string作为主键的类型。我们需要创建以下类,这些类将使用 anint来代替。我在一个文件中定义了以下所有类:AppUser.cs
public class AppUser :
IdentityUser<int, AppUserLogin, AppUserRole, AppUserClaim>,
IUser<int>
{
}
public class AppUserLogin : IdentityUserLogin<int> { }
public class AppUserRole : IdentityUserRole<int> { }
public class AppUserClaim : IdentityUserClaim<int> { }
public class AppRole : IdentityRole<int, AppUserRole> { }
It will also be useful, to have a custom ClaimsPrincipal, which will easily expose User's ID
拥有自定义 ClaimsPrincipal 也很有用,它可以轻松公开用户的 ID
public class AppClaimsPrincipal : ClaimsPrincipal
{
public AppClaimsPrincipal( ClaimsPrincipal principal ) : base( principal )
{ }
public int UserId
{
get { return int.Parse(this.FindFirst( ClaimTypes.Sid ).Value); }
}
}
2. Create a custom IdentityDbContext
2.创建自定义 IdentityDbContext
Our application's database context will extend IdentityDbContext, which implements by default all authentication-related DbSets. Even if DbContext.OnModelCreatingis an empty method, I am not sure about the IdentityDbContext.OnModelCreating, so when overriding, remember to call base.OnModelCreating( modelBuilder )AppDbContext.cs
我们的应用程序的数据库上下文将扩展IdentityDbContext,它默认实现所有与身份验证相关的 DbSet。即使DbContext.OnModelCreating是空方法,我也不确定IdentityDbContext.OnModelCreating,所以在覆盖时,记得调用base.OnModelCreating( modelBuilder )AppDbContext.cs
public class AppDbContext :
IdentityDbContext<AppUser, AppRole, int, AppUserLogin, AppUserRole, AppUserClaim>
{
public AppDbContext() : base("DefaultConnection")
{
// Here use initializer of your choice
Database.SetInitializer( new CreateDatabaseIfNotExists<AppDbContext>() );
}
// Here you define your own DbSet's
protected override void OnModelCreating( DbModelBuilder modelBuilder )
{
base.OnModelCreating( modelBuilder );
// Here you can put FluentAPI code or add configuration map's
}
}
3. Create custom UserStoreand UserManager, which will use above
3.创建自定义UserStore和UserManager,上面会用到
AppUserStore.cs
AppUserStore.cs
public interface IAppUserStore : IUserStore<AppUser, int>
{
}
public class AppUserStore :
UserStore<AppUser, AppRole, int, AppUserLogin, AppUserRole, AppUserClaim>,
IAppUserStore
{
public AppUserStore() : base( new AppDbContext() )
{
}
public AppUserStore(AppDbContext context) : base(context)
{
}
}
AppUserManager.cs
AppUserManager.cs
public class AppUserManager : UserManager<AppUser, int>
{
public AppUserManager( IAppUserStore store ) : base( store )
{
}
}
4. Modify AccountControllerto use your custom classes
4.修改AccountController为使用您的自定义类
Change all UserManagerto AppUserManager, UserStoreto AppUserStoreetc. Take an example of this constructors:
将所有更改UserManager为AppUserManager, UserStoretoAppUserStore等。以这个构造函数为例:
public AccountController()
: this( new AppUserManager( new AppUserStore( new AppDbContext() ) ) )
{
}
public AccountController(AppUserManager userManager)
{
UserManager = userManager;
}
5. Add user's ID as a claim to ClaimIdentitystored in a cookie
5. 将用户 ID 添加为ClaimIdentity存储在 cookie 中的声明
In step 1, we have created AppClaimsPrincipal, which exposes UserId taken out of ClaimType.Sid. However, to have this claim available, we need to add it, when logging in the user. In AccountControllera SingInAsyncmethod is responsible for logging in. We need to add a line to this method, to add the claim.
在第 1 步中,我们创建了AppClaimsPrincipal,它公开了从ClaimType.Sid. 但是,要使此声明可用,我们需要在用户登录时添加它。在AccountController一个SingInAsync方法中负责登录。我们需要在这个方法中添加一行,来添加声明。
private async Task SignInAsync(AppUser user, bool isPersistent)
{
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
ClaimsIdentity identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
// Extend identity claims
identity.AddClaim( new Claim( ClaimTypes.Sid, user.Id.ToString() ) );
AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
}
6. Create a BaseControllerwith a CurrentUserproperty
6.BaseController用CurrentUser属性创建一个
To have an easy access to a currently logged in user's ID in your controllers, create an abstract BaseController, from which your controllers will derive. In the BaseController, create a CurrentUseras follows:
要在您的控制器中轻松访问当前登录的用户 ID,请创建一个 abstract BaseController,您的控制器将从中派生。在 中BaseController,创建一个CurrentUser如下:
public abstract class BaseController : Controller
{
public AppClaimsPrincipal CurrentUser
{
get { return new AppClaimsPrincipal( ( ClaimsPrincipal )this.User ); }
}
public BaseController()
{
}
}
7. Inherit your controllers from BaseControllerand enjoy
7. 继承您的控制器BaseController并享受
From now on, you can use CurrentUser.UserIdin your controllers to access an ID of a currently logged in user without trips to the database. You can use it, to query only objects, which belong to the user.
从现在开始,您可以CurrentUser.UserId在控制器中使用来访问当前登录用户的 ID,而无需访问数据库。您可以使用它来仅查询属于用户的对象。
You don't have to take care of auto generation of user primary keys - no surprise, Entity Framework by default uses Identity for integer primary keys, when creating tables.
您不必处理用户主键的自动生成 - 毫不奇怪,在创建表时,实体框架默认使用 Identity 作为整数主键。
Warning!Keep in mind, that if you implement it in already released project, for already logged in users ClaimsType.Sidwill not exist and FindFirstwill return null in AppClaimsPrincipal. You need to either force logout all users or handle this scenario in AppClaimsPrincipal
警告!请记住,如果您在已发布的项目中实现它,对于已经登录的用户ClaimsType.Sid将不存在并且FindFirst将在AppClaimsPrincipal. 您需要强制注销所有用户或在AppClaimsPrincipal
回答by Stefan Cebulak
@HaoKung
@HaoKung
I've succeeded to make int id's with your nightly builds. User.Identity.GetUserId() problem is still there, but i just did int.parse() for now.
我已经成功地用你的夜间构建制作了 int id。User.Identity.GetUserId() 问题仍然存在,但我现在只是做了 int.parse()。
The biggest suprise was that i did not need to create ID by myself, db was made with identity id and it was somehow automatically set for new users Oo...
最大的惊喜是我不需要自己创建 ID,db 是用身份 ID 创建的,它以某种方式自动为新用户设置 Oo ...
Model:
模型:
public class ApplicationUser : IdentityUser<int, IntUserLogin, IntUserRole, IntUserClaim>
{
public ApplicationUser()
{
}
public ApplicationUser(string name) : this() { UserName = name; }
}
public class ApplicationDbContext : IntUserContext
{
public ApplicationDbContext()
{
}
}
private class IntRole : IdentityRole<int, IntUserRole>
{
public IntRole()
{
}
public IntRole(string name) : this() { Name = name; }
}
private class IntUserRole : IdentityUserRole<int> { }
private class IntUserClaim : IdentityUserClaim<int> { }
private class IntUserLogin : IdentityUserLogin<int> { }
private class IntUserContext : IdentityDbContext<ApplicationUser, IntRole, int, IntUserLogin, IntUserRole, IntUserClaim>
{
public IntUserContext()
: base("DefaultConnection")
{
}
}
private class IntUserStore : UserStore<ApplicationUser, IntRole, int, IntUserLogin, IntUserRole, IntUserClaim>
{
public IntUserStore(DbContext context)
: base(context)
{
}
}
private class IntRoleStore : RoleStore<IntRole, int, IntUserRole>
{
public IntRoleStore(DbContext context)
: base(context)
{
}
}
Controller:
控制器:
public AccountController()
: this(new UserManager<ApplicationUser, int>(new IntUserStore(new ApplicationDbContext())))
{
}
public AccountController(UserManager<ApplicationUser, int> userManager)
{
UserManager = userManager;
}
public UserManager<ApplicationUser, int> UserManager { get; private set; }
Hope release build will come soon :D...
希望发布版本很快就会到来:D ...
P.S. Can't write comments so i did an answer, sorry.
PS 不能写评论所以我做了一个回答,抱歉。
回答by Manik Arora
As stated here:
如前所述这里:
In Visual Studio 2013, the default web application uses a string value for the key for user accounts. ASP.NET Identity enables you to change the type of the key to meet your data requirements. For example, you can change the type of the key from a string to an integer.
在 Visual Studio 2013 中,默认 Web 应用程序使用字符串值作为用户帐户的密钥。ASP.NET Identity 使您能够更改密钥的类型以满足您的数据要求。例如,您可以将键的类型从字符串更改为整数。
This topic on the above link shows how to start with the default web application and change the user account key to an integer. You can use the same modifications to implement any type of key in your project. It shows how to make these changes in the default web application, but you could apply similar modifications to a customized application. It shows the changes needed when working with MVC or Web Forms.
上面链接中的这个主题展示了如何从默认 Web 应用程序开始并将用户帐户密钥更改为整数。您可以使用相同的修改在您的项目中实现任何类型的键。它展示了如何在默认 Web 应用程序中进行这些更改,但您可以对自定义应用程序应用类似的修改。它显示了使用 MVC 或 Web 窗体时所需的更改。
回答by lyz
Basically you have to :
基本上你必须:
-Change the type of the key to int in the Identity user class
-Add customized Identity classes that use int as key
-Change the context class and user manager to use int as key
-Change start-up configuration to use int as key
-Change the AccountController to pass int as key
-在Identity用户类中将key的类型更改为int -添加
使用int作为key的自定义Identity类 -
将上下文类和用户管理器更改为使用int作为key -
将启动配置更改为使用int作为key
-Change将 int 作为键传递的 AccountController
hereis link where all steps are explained to achieve this.
这是链接,其中解释了实现此目的的所有步骤。

