Search code examples
asp.net-mvcentity-frameworkasp.net-mvc-5owinasp.net-identity

How to change type of id in Microsoft.AspNet.Identity.EntityFramework.IdentityUser


(ASP.NET MVC 5, EF6, VS2013)

I'm trying to figure out how to change the type of the "Id" field from string to int in the type:

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:

(from 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?

An explanation of why I don't want to store GUIDs for ids in the user table:

-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.)

-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.)

Thanks...

-Ben


Solution

  • 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.

    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.

    Updated with 1.1-alpha1 example: How to get nightly builts

    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

        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);
            }
        }