Identity: 2.0 Migration Questions/Issues

Created on 15 Aug 2017  路  78Comments  路  Source: aspnet/Identity

Consolidated thread for any migration questions and issues for identity

Official migration doc: https://docs.microsoft.com/en-us/aspnet/core/migration/1x-to-2x/identity-2x

discussion

Most helpful comment

I'm pretty confused by migrating custom user types as in https://github.com/aspnet/Identity/issues/1001.

So, just like that scenario I have a custom User object, but everything else just uses a Guid Key.

So I do this...

        services.AddIdentity<User, IdentityRole<Guid>>()
        .AddEntityFrameworkStores<REV23DbContext>()
        .AddDefaultTokenProviders();

And get this..

'AddEntityFrameworkStores can only be called with a role that derives from IdentityRole.'

I don't see anywhere that IdentityRole has the TRoleClaim on it? Don't really get what this means.

All 78 comments

I'm pretty confused by migrating custom user types as in https://github.com/aspnet/Identity/issues/1001.

So, just like that scenario I have a custom User object, but everything else just uses a Guid Key.

So I do this...

        services.AddIdentity<User, IdentityRole<Guid>>()
        .AddEntityFrameworkStores<REV23DbContext>()
        .AddDefaultTokenProviders();

And get this..

'AddEntityFrameworkStores can only be called with a role that derives from IdentityRole.'

I don't see anywhere that IdentityRole has the TRoleClaim on it? Don't really get what this means.

I was using services.AddIdentity<User, IdentityRole<int>> in ConfigureServices and started getting the error after moving to ASP.NET Core 2.0.

I changed my code to use a user-defined Role class instead of the generic IdentityRole<int> and it's working now.

I created a class MyRole inheriting from IdentityRole<int>:

public class MyRole : IdentityRole<int>
{
    public MyRole() : base()
    {
    }

    public MyRole(string roleName)
    {
        Name = roleName;
    }
}

and changed ConfigureServices to use that class instead of the generic IdentityRole<int>:

services.AddIdentity<User, MyRole>

Apparently AddEntityFrameworkStores checks the type for the Role class used in services.AddIdentity<User, Role> and returns null if it's not a derived class or if it is a generic IdentityRole<T> (even if it has the correct type parameter).

Hope this helps and appreciate anyone else shedding more light on this issue.

Here's what I've faced so far.

screen shot 2017-08-18 at 2 09 04 am

Didn't modify anything related to roles...

An unhandled exception occurred while processing the request.

InvalidOperationException: Cannot create a DbSet for 'IdentityRole' because this type is not included in the model for the context.
Microsoft.EntityFrameworkCore.Internal.InternalDbSet.get_EntityType()

Stack Query Cookies Headers
InvalidOperationException: Cannot create a DbSet for 'IdentityRole' because this type is not included in the model for the context.
Microsoft.EntityFrameworkCore.Internal.InternalDbSet.get_EntityType()
Microsoft.EntityFrameworkCore.Internal.InternalDbSet.get_EntityQueryable()
Microsoft.EntityFrameworkCore.Internal.InternalDbSet.System.Linq.IQueryable.get_Expression()
System.Linq.Queryable.GetSourceExpression<TSource>(IEnumerable<TSource> source)
System.Linq.Queryable.Join<TOuter, TInner, TKey, TResult>(IQueryable<TOuter> outer, IEnumerable<TInner> inner, Expression<Func<TOuter, TKey>> outerKeySelector, Expression<Func<TInner, TKey>> innerKeySelector, Expression<Func<TOuter, TInner, TResult>> resultSelector)
Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore+<GetRolesAsync>d__36.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Microsoft.AspNetCore.Identity.UserManager+<GetRolesAsync>d__110.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Microsoft.AspNetCore.Identity.UserClaimsPrincipalFactory+<GenerateClaimsAsync>d__5.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Microsoft.AspNetCore.Identity.UserClaimsPrincipalFactory+<CreateAsync>d__9.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Microsoft.AspNetCore.Identity.SignInManager+<CreateUserPrincipalAsync>d__25.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Microsoft.AspNetCore.Identity.SignInManager+<SignInAsync>d__30.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Identity.SignInManager+<SignInOrTwoFactorAsync>d__52.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Microsoft.AspNetCore.Identity.SignInManager+<PasswordSignInAsync>d__33.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Microsoft.AspNetCore.Identity.SignInManager+<PasswordSignInAsync>d__34.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Volt.Controllers.AccountController+<Login>d__8.MoveNext() in AccountController.cs
+
                var result = await _signInManager.PasswordSignInAsync(user.UserName, model.Password, model.RememberMe, false);
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker+<InvokeActionMethodAsync>d__12.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker+<InvokeNextActionFilterAsync>d__10.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context)
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker+<InvokeInnerFilterAsync>d__14.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker+<InvokeNextResourceFilter>d__22.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker+<InvokeFilterPipelineAsync>d__17.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker+<InvokeAsync>d__15.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Builder.RouterMiddleware+<Invoke>d__4.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware+<Invoke>d__6.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Volt.Sockets.VoltSocketMiddleware+<Invoke>d__3.MoveNext() in VoltSocketMiddleware.cs
+
            await _next.Invoke(context);
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware+<Invoke>d__3.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.MigrationsEndPointMiddleware+<Invoke>d__4.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware+<Invoke>d__6.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware+<Invoke>d__6.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware+<Invoke>d__7.MoveNext()

It looks like there's a bug with AddEntityFrameworkStores that prevents using the generic base IdentityRole directly, @pealmeid 's workaround of using a dervied TRole should work

@nixxholas what's your startup look like? particularly the AddIdentity section?

@madmunsterdaddy you need to do the same thing, introduce a dervied class MyRole: IdentityRole<Guid> to workaround the bug preventing the base generic from being used directly.

@HaoK

            // Identity Configurations.
            services.AddIdentity<User, IdentityRole<string>>(config =>
                {
                    // config.SignIn.RequireConfirmedEmail = true;
                    config.SignIn.RequireConfirmedPhoneNumber = true;
                })
                .AddEntityFrameworkStores<VoltDbContext>()
                .AddDefaultTokenProviders()
                .AddUserManager<VoltUserManager<User>>();

I do not want to mess with this migration as it means a lot to me. I do not see any recommendations/guides on this after implementing a derived role class.

An unhandled exception occurred while processing the request.

InvalidOperationException: Cannot create a DbSet for 'UserRole' because this type is not included in the model for the context.

Added the Derived role to the ApplicationDbContext equivalent on my project.

Twilio is now broken on .NET Core 2.0 with .NET Core 1.1 implementations.

Cookie.SecurePolicy value in AddApplications method is set to

options.Cookie.SecurePolicy = CookieSecurePolicy.Always;

Which means HTTPS only and local development will also need to be done with HTTPS urls.
I'm sure you will see these kind of issues very quickly:

  • I can't login anymore.
  • PasswordSignInAsync doesn't work anymore.
  • PasswordSignInAsync doesn't set any cookies at all.
  • I keep getting re-directed back to the login page.

It would be better to set it to

CookieSecurePolicy.SameAsRequest

Solution:

// should be added after the  AddIdentity
services.ConfigureApplicationCookie(identityOptionsCookies =>
{
   identityOptionsCookies.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
});

This will no longer generate a user friendly token for the user to input in conjunction with Twilio.

var code = await _userManager.GenerateChangePhoneNumberTokenAsync(user, model.PhoneNumber);

We have extended SignInManager and created an override for
public override async Task SignInAsync(TUser user, bool isPersistent, string authenticationMethod = null){}

When we call
var scheme = await SchemeProvider.GetSchemeAsync(Microsoft.AspNetCore.Identity.IdentityConstants.ExternalScheme);
await Context.Authentication.GetAuthenticateInfoAsync(scheme.Name);

The code throws an exception stating that it cannot find a authentication scheme. The scheme.Name value is Identity.External.

Any ideas?

Ok, created my new derived type per @HaoK

public class Role : IdentityRole<Guid>
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public Role()
    {
        Id = Guid.NewGuid();
    }
}

Then I use it in AddIdentity

        services.AddIdentity<User, Role>(o =>
        {                
            o.Password.RequireDigit = false;
            o.Password.RequiredLength = 8;                
            o.Password.RequireLowercase = false;
            o.Password.RequireNonAlphanumeric = false;                
            o.Password.RequireUppercase = false;                
        })
        .AddEntityFrameworkStores<REV23DbContext>()
        .AddDefaultTokenProviders();

Then try to add it to the model

    protected override void OnModelCreating(ModelBuilder builder)
    {            
        base.OnModelCreating(builder);

        builder.Entity<User>().ToTable("User").HasKey(u => u.Id);
        builder.Entity<Role>().ToTable("Role").HasKey(r => r.Id);

But I get:

InvalidOperationException: A key cannot be configured on 'Role' because it is a derived type. The key must be configured on the root type 'IdentityRole'. If you did not intend for 'IdentityRole' to be included in the model, ensure that it is not included in a DbSet property on your context, referenced in a configuration call to ModelBuilder, or referenced from a navigation property on a type that is included in the model.

If I try to remove the HasKey call, then Add-Migration attempts to recreate AspNetRole table.

Are there any good steps to take here, or am I just blocked by this bug?

@HaoK ....

UPDATE: I have solved the problem by adding a JsonClaimsPrincipalConverter, which is used to suppress most serialization for the ClaimsPrincipal classes when saving to Cosmos DB. This feels a bit hacky, but I suspect it is OK since I don't have a need for the information in the application at this time. Any thoughts from Microsoft on this?

I am having an issue with serializing the logins, which was detected by my automated tests. Prior to migrating to 2.0, everything was working perfectly, but I now receive the error below when calling the result = await _userManager.AddLoginAsync(user, info); inside the AccountController.ExternalLoginConfirmation method.

I am using the DocumentDBUserStore from codekoenig (https://github.com/codekoenig/AspNetCore.Identity.DocumentDb) to store my users, roles, logins, etc. in Cosmos DB rather than the default SQL provider.

It looks like the problem occurs when attempting to serialize the System.Security.Claims.ClaimsPrincipal class. I don't see any release notes regarding changes to this class, so it is difficult to figure out what is happening.

Anyone else seeing something similar? This is the only issue I have with Core 2.0.

Here is the stack trace I receive:

An unhandled exception occurred while processing the request.

PlatformNotSupportedException: This instance contains state that cannot be serialized and deserialized on this platform.
System.Security.Claims.ClaimsPrincipal.OnSerializingMethod(StreamingContext context)

TargetInvocationException: Exception has been thrown by the target of an invocation.
System.RuntimeMethodHandle.InvokeMethod(object target, Object[] arguments, Signature sig, bool constructor)

Stack Query Cookies Headers
PlatformNotSupportedException: This instance contains state that cannot be serialized and deserialized on this platform.
System.Security.Claims.ClaimsPrincipal.OnSerializingMethod(StreamingContext context)

Show raw exception details
TargetInvocationException: Exception has been thrown by the target of an invocation.
System.RuntimeMethodHandle.InvokeMethod(object target, Object[] arguments, Signature sig, bool constructor)
System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(object obj, Object[] parameters, Object[] arguments)
Newtonsoft.Json.Serialization.JsonContract+<>c__DisplayClass57_0.b__0(object o, StreamingContext context)
Newtonsoft.Json.Serialization.JsonContract.InvokeOnSerializing(object o, StreamingContext context)
Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.OnSerializing(JsonWriter writer, JsonContract contract, object value)
Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeList(JsonWriter writer, IEnumerable values, JsonArrayContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter, object value, Type objectType)
Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter, object value, Type objectType)
Newtonsoft.Json.Linq.JToken.FromObjectInternal(object o, JsonSerializer jsonSerializer)
Newtonsoft.Json.Linq.JObject.FromObject(object o, JsonSerializer jsonSerializer)
Microsoft.Azure.Documents.Document.FromObject(object document, JsonSerializerSettings settings)
Microsoft.Azure.Documents.Client.DocumentClient+d__150.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Microsoft.Azure.Documents.BackoffRetryUtility+<>c__DisplayClass1_0+<b__0>d.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Microsoft.Azure.Documents.BackoffRetryUtility+d__3.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
Microsoft.Azure.Documents.BackoffRetryUtility+d__3.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Microsoft.Azure.Documents.BackoffRetryUtility+d__1.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Microsoft.Azure.Documents.Client.DocumentClient+d__149.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Lrnen.Web.Online.Data.DocumentDbUserStore+d__15.MoveNext() in DocumentDBUserStore.cs
+
await documentClient.ReplaceDocumentAsync(GenerateDocumentUri(user.Id), document: user);
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Microsoft.AspNetCore.Identity.UserManager+d__171.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Microsoft.AspNetCore.Identity.UserManager+d__96.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Lrnen.Web.Online.Controllers.AccountController+d__12.MoveNext() in AccountController.cs
+
result = await _userManager.AddLoginAsync(user, info);
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker+d__12.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker+d__10.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context)
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker+d__14.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker+d__22.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker+d__17.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker+d__15.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Builder.RouterMiddleware+d__4.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware+d__6.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.MigrationsEndPointMiddleware+d__4.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware+d__6.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware+d__6.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware+d__7.MoveNext()

Show raw exception details

I'm trying to migrate from .NET Core 1.1 to 2.0 following the migrations guide and I'm getting the following exception:

System.Data.SqlClient.SqlException (0x80131904): Invalid column name 'UserId'.

Like other people in this thread, I have the following:

services.AddIdentity<User, IdentityRole<int>>()
    .AddDefaultTokenProviders();

So this exception gets thrown when I call this:

await signInManager.PasswordSignInAsync(userName, password, isPersisten, lockoutOnFailure)

Anyway, you guys are telling us

The Entity Framework Core navigation properties of the base IdentityUser POCO (Plain Old CLR Object) have been removed. If your 1.x project used these properties, manually add them back to the 2.0 project

So I've added the following navigation property to my User : IdentityUser POCO class:

public virtual ICollection<TUserRole> Roles { get; } = new List<TUserRole>();

When I add a migration I'm getting the following:

protected override void Up(MigrationBuilder migrationBuilder)
{
    migrationBuilder.AddColumn<int>(
        name: "UserId",
        table: "AspNetRoles",
        type: "int",
        nullable: true);

    migrationBuilder.CreateIndex(
        name: "IX_AspNetRoles_UserId",
        table: "AspNetRoles",
        column: "UserId");

    migrationBuilder.AddForeignKey(
        name: "FK_AspNetRoles_AspNetUsers_UserId",
        table: "AspNetRoles",
        column: "UserId",
        principalTable: "AspNetUsers",
        principalColumn: "Id",
        onDelete: ReferentialAction.Restrict);
}

I'm guessing I also have to configure this change, but there is no documentation for this change. I was using the Roles property on the IdentityUser class in v1.1, so I need this back, since the application is already running in production.
What's the correct way to configure this (in Fluent API?)? Because a many-to-many table is between the AspNetUsers and AspNetRoles tables in the sql database.
Perhaps this should be documentated in the migration guide, since I'm at a loss here.

@HaoK Can we get the configuration needed for the navigation properties added to the guide? See also https://github.com/aspnet/EntityFrameworkCore/issues/9503

The overload for configuring the application user primary key type has been removed from IdentityEntityFrameworkBuilderExtensions.cs

AddEntityFrameworkStores<TContext, TKey>()

This breaking change is not mentioned in the migration docs. What is the fix please?

Just call AddEntityFrameworkStores<TContext> it should be smart enough to infer what's needed now

@scottaddie can we update the official identity migration doc to include the additional snippet that is needed for people who were relying on the navigation properties?

```// where Role and User are the actual types
builder.Entity()
.HasMany(e => e.Claims)
.WithOne()
.HasForeignKey(e => e.RoleId)
.IsRequired()
.OnDelete(DeleteBehavior.Cascade);

builder.Entity()
.HasMany(e => e.Users)
.WithOne()
.HasForeignKey(e => e.RoleId)
.IsRequired()
.OnDelete(DeleteBehavior.Cascade);

builder.Entity()
.HasMany(e => e.Claims)
.WithOne()
.HasForeignKey(e => e.UserId)
.IsRequired()
.OnDelete(DeleteBehavior.Cascade);

builder.Entity()
.HasMany(e => e.Logins)
.WithOne()
.HasForeignKey(e => e.UserId)
.IsRequired()
.OnDelete(DeleteBehavior.Cascade);

builder.Entity()
.HasMany(e => e.Roles)
.WithOne()
.HasForeignKey(e => e.UserId)
.IsRequired()
.OnDelete(DeleteBehavior.Cascade);
```

@HaoK @ajcvickers I'm not sure that's the correct way to configure the many-to-many table?

The database schema looked like this pre-2.0:

capture

You can see the many-to-many table dbo.AspNetUserRoles that connects dbo.AspNetRoles and dbo.AspNetUsers.

If I try to configure the User entity like so:

capture

Then I'm getting the error:

'IdentityRole<int>' does not contain a definition for 'UserId' and no extension method 'UserId' accepting a first argument of type 'IdentityRole<int>' could be found (are you missing a using directive or an assembly reference?)

The same applies for configuring the other end:

capture

with error:

'IdentityRole<int>' does not contain a definition for 'Users' and no extension method 'Users' accepting a first argument of type 'IdentityRole<int>' could be found (are you missing a using directive or an assembly reference?)

So what's the correct and recommended way to migrate this?

Hello,

Trying to complete the migration to 2.0.

I'm getting the following error on Startupcs:

'IdentityBuilder' does not contain a definition for 'AddDefaultTokenProviders' nor is there any extension method 'AddDefaultTokenProviders' that accepts a first argument of type 'IdentityBuilder' (are missing some using directive or an assembly reference?)

Did the package that contains 'AddDefaultTokenProviders' changed? is there a new reference one must add?

Hello,

In the previous version I was able to feed my model the number of Users from the Identity package, specifically IdentityRole:

            model = roleManager.Roles.Select(r => new ApplicationRoleListviewModel
            {
                RoleName = r.Name,
                Id = r.Id,
                Description = r.Description,
                NumberOfUsers = r.Users.Count
            }).ToList();

Now there is an error mentioning that Users is not defined. Was this property deleted or moved?

Name and Id is extracted from:

namespace Microsoft.AspNetCore.Identity
{
public class IdentityRole<TKey> where TKey : IEquatable<TKey>
  {
      public IdentityRole();
      public IdentityRole(string roleName);
      public virtual TKey Id { get; set; }
      public virtual string Name { get; set; }
      public virtual string NormalizedName { get; set; }
      public virtual string ConcurrencyStamp { get; set; }
      public override string ToString();
  }
}

Description property is a property defined by me on this project.

Thanks

Yes the navigation properties were removed from the base pocos, you will need to add them back to your TUser class if you were using

Thanks, HaoK, is good to have a reply for all these changes.

I'm very new to this world and I'm very much self taught. Is there any guide you can share with me about how to add them back?

Update:
Also, I believe I extracted this info from the TRole class.

You should be able to follow the steps here: https://github.com/aspnet/EntityFrameworkCore/issues/9503

@HaoK @ajcvickers is my question and issue being ignored?

@QuantumHive have you tried the steps in https://github.com/aspnet/EntityFrameworkCore/issues/9503 to add back the navigation properties and configure the model as described in the workaround there?

@HaoK I've written an entire explanation (even provided with screenshots) that those steps do not work. Did nobody care or read that? Obviously the steps in https://github.com/aspnet/EntityFrameworkCore/issues/9503 don't work. If I need to provide more information of why the migration process doesn't work, then please tell me that. All I try to do is contribute to the process of migrating to 2.0, so that future users already have an answer.

From the errors you are getting it looks like your navigation properties might not be typed properly, they should be typed like this

public virtual ICollection<IdentityUserRole<int>> Roles { get; } = new List<IdentityUserRole<int>>();
public virtual ICollection<IdentityUserClaim<int>> Claims { get; } = new List<IdentityUserClaim<int>>();
public virtual ICollection<IdentityUserLogin<int>> Logins { get; } = new List<IdentityUserLogin<int>>();

For Users/Roles entity configuration, e should be IdentityUserRole<int>, not IdentityRole<int> which is why you are getting errors about UserId.

@HaoK sorry, my bad. I've overlooked the type. It works now, my migration is complete.

We are still stuck/blocked re how to migrate this:

            services.AddIdentity<UserEntity, UserRoleEntity>()
                .AddEntityFrameworkStores<HotelApiContext, Guid>()
                .AddDefaultTokenProviders();

As we get error re ....cannot be inferred by usage, if we remove the params.
Thanks in advance for any further suggestions.

Many thanks, we were able to solve it using that test as a reference.

Ok, I'm FINALLY getting closer with my Guid based Role, but now I'm getting this.

The key value at position 0 of the call to 'DbSet>.Find' was of type 'Guid', which does not match the property type of 'string'.

And my migration inexplicably contains this:

migrationBuilder.AddForeignKey(
name: "FK_UserToken_User_UserId",
table: "UserToken",
column: "UserId",
principalTable: "User",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);

Which I already have a FK on there for User.Id. So possibly related. Any ideas what's up here?

        builder.Entity<User>().ToTable("User").HasKey(u => u.Id);
        builder.Entity<Role>().ToTable("Role").HasKey(u => u.Id);
        builder.Entity<IdentityUserClaim<Guid>>().ToTable("UserClaim").HasKey(uc => uc.Id);
        builder.Entity<IdentityUserLogin<Guid>>().ToTable("UserLogin").HasKey(ul => new { ul.LoginProvider, ul.ProviderKey });
        builder.Entity<IdentityUserRole<Guid>>().ToTable("UserRole").HasKey(ur => new { ur.UserId, ur.RoleId }); ;
        builder.Entity<IdentityRoleClaim<Guid>>().ToTable("RoleClaim").HasKey(rc => rc.Id);
        builder.Entity<IdentityUserToken<Guid>>().ToTable("UserToken").HasKey(ut => new { ut.LoginProvider, ut.UserId, ut.Name });

What is your DbContext deriving from? IdentityDbContext<TUser, TRole, Guid>?

Yep! IdentityDbContext

@chadwackerman2 yep no probs.

In Startup:

services.AddIdentity<UserEntity, UserRoleEntity>() .AddEntityFrameworkStores<BodiMeAPIContext>() .AddDefaultTokenProviders();

and everything else:

    public class BodiMeAPIContext : IdentityDbContext<UserEntity, UserRoleEntity, Guid>
    {
        public BodiMeAPIContext(DbContextOptions options)
            : base(options) { }

        public virtual DbSet<BodyEntity> Body { get; set; }
        public virtual DbSet<BodyMeasurementEntity> Measurements { get; set; }
    }

    public class UserEntity : IdentityUser<Guid>
    {
        public string FirstName { get; set; }

        public string LastName { get; set; }

        public DateTimeOffset CreatedAt { get; set; }
    }

    public class UserRoleEntity : IdentityRole<Guid>
    {
        public UserRoleEntity()
            : base()
        { }

        public UserRoleEntity(string roleName)
            : base(roleName)
        { }
    }

Good luck with it

What happened to the Domain portion of User.Identity.Name when using Windows Authentication? It's just giving me username, without the domain portion?

I got GSNETX\twilliams before, and now I just get twilliams

How do I get access back to the domain portion?

I can still see it's around there somewhere, but not sure how to directly access it.

User.Claims.ToList()
Count = 6
    [0]: {http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier: GSNETX\twilliams}
    [1]: {http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name: twilliams}

I could do something like this
PlatformUser user = await userManager.FindByIdAsync(User.FindFirst(ClaimTypes.NameIdentifier).Value);

Instead of this
PlatformUser user = await userManager.FindByIdAsync(User.Identity.Name);

But the latter is preferable for me?

@HaoK How do I override AspNet* table names if I am starting from scratch with 2.0 and having User and Role classes, and int as key.

ApplicationDbContext : IdentityDbContext<User, Role, int>

public class User : IdentityUser<int>

public class Role : IdentityRole<int>
    {
    }

  services.AddDbContext<ApplicationDbContext>(options =>
                options.UseNpgsql(_connectionString));

            services.AddIdentity<User, Role>()
                .AddEntityFrameworkStores<ApplicationDbContext>()
                .AddDefaultTokenProviders();

If I try this

builder.Entity<User>().ToTable(nameof(Users));
builder.Entity<Role>().ToTable(nameof(Roles));
builder.Entity<IdentityUserClaim<int>>().ToTable("UserClaims").HasKey(uc => uc.Id);
builder.Entity<IdentityUserLogin<int>>().ToTable("UserLogins").HasKey(ul => ul.UserId);
builder.Entity<IdentityUserRole<int>>().ToTable("UserRoles").HasKey(ur => new { ur.UserId, ur.RoleId }); ;
builder.Entity<IdentityRoleClaim<int>>().ToTable("RoleClaims").HasKey(rc => rc.Id);
builder.Entity<IdentityUserToken<int>>().ToTable("UserTokens").HasKey(ut => ut.UserId );

then I get _ApplicationRoleId_ and _ApplicationUserId_ keys in other tables, along with UserId and RoleId. And no, I don't have ApplicationUser or ApplicationRole anywhere in my application.

Are you sure there aren't any old migrations or anything like that laying around?

@haok Yeah, I deleted Migrations folder, dropped the database, cleaned solution and even removed bin/obj folders. 馃槃

I double-checked with a new project.

builder.Entity<ApplicationRole>(entity => { entity.HasMany(x => x.Users).WithOne().HasForeignKey(ur => ur.RoleId).IsRequired(); entity.ToTable("MyRoles", "dbo"); });
i use this code to rename AspNetRoles tables to MyRoles but in migration it renames tables as ApplicationRole. It was working in core 1.1. After upgrading to core 2.0 doesn't work. How can i do?

solved by changing IdentityDbContext:
public class ApplicationDbContext : IdentityDbContext,IdentityUserToken>

but still have duplicated foreign keys

I still don't get what to do with this one when trying to sign in after upgrade. @HaoK?

Or is this part of the registration not detecting my custom Guid mapping bug?

ArgumentException: The key value at position 0 of the call to 'DbSet>.Find' was of type 'Guid', which does not match the property type of 'string'.
Microsoft.EntityFrameworkCore.Internal.EntityFinder.FindTracked(Object[] keyValues, out IReadOnlyList keyProperties)
Microsoft.EntityFrameworkCore.Internal.EntityFinder.FindAsync(Object[] keyValues, CancellationToken cancellationToken)
Microsoft.EntityFrameworkCore.Internal.InternalDbSet.FindAsync(Object[] keyValues, CancellationToken cancellationToken)
Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore.FindTokenAsync(TUser user, string loginProvider, string name, CancellationToken cancellationToken)
Microsoft.AspNetCore.Identity.UserStoreBase+d__67.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Microsoft.AspNetCore.Identity.AuthenticatorTokenProvider+d__0.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Microsoft.AspNetCore.Identity.UserManager+d__130.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Microsoft.AspNetCore.Identity.SignInManager+d__52.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Microsoft.AspNetCore.Identity.SignInManager+d__33.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Microsoft.AspNetCore.Identity.SignInManager+d__34.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
REV23.Web.Controllers.AccountController+d__9.MoveNext() in AccountController.cs
+
var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: true);

@madmunsterdaddy Is your db context specifying the correct generic arguments? Looks like that error would be a mismatch between IdentityUserToken and IdentityUserToken<Guid> Can you include what your dbcontext looks like?

@HaoK yep. It always used to work... Even tried to full on IdentityDbContextOverload specifying everything with no success.

public class REV23DbContext : IdentityDbContext<User, Role, Guid>
{

....
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// Customize the ASP.NET Identity model and override the defaults if needed.
// For example, you can rename the ASP.NET Identity table names and more.
// Add your customizations after calling base.OnModelCreating(builder);
builder.Entity().ToTable("User").HasKey(u => u.Id);
builder.Entity().ToTable("Role").HasKey(u => u.Id);
builder.Entity>().ToTable("UserClaim").HasKey(uc => uc.Id);
builder.Entity>().ToTable("UserLogin").HasKey(ul => new { ul.LoginProvider, ul.ProviderKey });
builder.Entity>().ToTable("UserRole").HasKey(ur => new { ur.UserId, ur.RoleId }); ;
builder.Entity>().ToTable("RoleClaim").HasKey(rc => rc.Id);
builder.Entity>().ToTable("UserToken").HasKey(ut => new { ut.LoginProvider, ut.UserId, ut.Name });

Try extending from IdentityDbContext<User, Role, Guid, IdentityUserClaim<Guid>, IdentityUserRole<Guid>,IdentityUserLogin<Guid>,IdentityRoleClaim<Guid>,IdentityUserToken<Guid> and updating your OnModelCreating to the same types as well

Yeah, that was what I had already tried. Did again, with same results :(

My OnModelCreating does have the \

    protected override void OnModelCreating(ModelBuilder builder)
    {            
        base.OnModelCreating(builder);
        // Customize the ASP.NET Identity model and override the defaults if needed.
        // For example, you can rename the ASP.NET Identity table names and more.
        // Add your customizations after calling base.OnModelCreating(builder);
        builder.Entity<User>().ToTable("User").HasKey(u => u.Id);
        builder.Entity<Role>().ToTable("Role").HasKey(u => u.Id);
        builder.Entity<IdentityUserClaim<Guid>>().ToTable("UserClaim").HasKey(uc => uc.Id);
        builder.Entity<IdentityUserLogin<Guid>>().ToTable("UserLogin").HasKey(ul => new { ul.LoginProvider, ul.ProviderKey });
        builder.Entity<IdentityUserRole<Guid>>().ToTable("UserRole").HasKey(ur => new { ur.UserId, ur.RoleId }); ;
        builder.Entity<IdentityRoleClaim<Guid>>().ToTable("RoleClaim").HasKey(rc => rc.Id);
        builder.Entity<IdentityUserToken<Guid>>().ToTable("UserToken").HasKey(ut => new { ut.LoginProvider, ut.UserId, ut.Name });

Try getting rid of your own db context entirely and just use IdentityDbContext<User, Role, Guid, IdentityUserClaim<Guid>, IdentityUserRole<Guid>,IdentityUserLogin<Guid>,IdentityRoleClaim<Guid>,IdentityUserToken<Guid> to see if that makes things work.

Where would I do that? In AddEntityFrameworkStores? Nothing seems to like that definition as far as setting it up is concerned.

I just mean to narrow down what could be causing the issue, you can try directly using the base identity dbcontext instead of wherever you are using REV23DbContext. You should be able to use it as your TContext in AddEntityFrameworkStores<>. Alternatively it should be more or less equivalent to just define your context as an empty (ctor only) subclass to see if that makes things work as well:

public class REV23DbContext : IdentityDbContext<User, Role, Guid, IdentityUserClaim<Guid>, IdentityUserRole<Guid>,IdentityUserLogin<Guid>,IdentityRoleClaim<Guid>,IdentityUserToken<Guid>

Also just to double check, your User/Role are deriving from IdentityUser<Guid> and IdentityRole<Guid> right?

I see.. yeah, that's what that is currently inherting.

And yep. Those look like this:

public class Role : IdentityRole<Guid>
{

...
}

// Add profile data for application users by adding properties to the ApplicationUser class
public class User : IdentityUser<Guid>
{

..
}

I think it might have something to do with the fact that my Migration to this release adds this FK?

        migrationBuilder.AddForeignKey(
            name: "FK_UserToken_User_UserId",
            table: "UserToken",
            column: "UserId",
            principalTable: "User",
            principalColumn: "Id",
            onDelete: ReferentialAction.Cascade);

Which I don't understand, as new DB doesn't have that FK. I don't have a navigation property or anything to UserTokens from User.

Well there should be a FK relationship between the User and UserTokens, just like the other child entities, i.e. UserClaims/UserRoles

And that makes sense-- but when creating a new Identity database with a new webapplication, no such FK exists, which threw me off... unless I missed it.

I guess I'll need to wait until the fixes in 2.01 to see if this fixes my issue because I'm stumped at this point :(

The fixes are only at the higher level sugar apis, you should be able to directly add the correct UserStore type:

Just don't call AddEntityFrameworkStores and instead directly add the store (replacing the TEntities with the actual types you have in your model:

services.AddScoped<IUserStore<TUser>, UserStore<TUser, TRole, TContext, TKey, TUserClaim, TUserRole, TUserLogin, TUserToken, TRoleClaim>>()

And similarly for the RoleStore if you are using role manager.

@HaoK Was able to reproduce the error in a blank solution. I think there is an issue here.

ArgumentException: The key value at position 0 of the call to 'DbSet.Find' was of type 'Guid', which does not match the property type of 'string'.

Basically, start a new project with individual auth.

public class User : IdentityUser<Guid>
{
    public string MyProperty { get; set; }
}

public class Role : IdentityRole<Guid>
{
    public string MyProperty { get; set; }
}

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);

        builder.Entity<User>().ToTable("User").HasKey(u => u.Id);
        builder.Entity<Role>().ToTable("Role").HasKey(u => u.Id);
        builder.Entity<IdentityUserClaim<Guid>>().ToTable("UserClaim").HasKey(uc => uc.Id);
        builder.Entity<IdentityUserLogin<Guid>>().ToTable("UserLogin").HasKey(ul => new { ul.LoginProvider, ul.ProviderKey });
        builder.Entity<IdentityUserRole<Guid>>().ToTable("UserRole").HasKey(ur => new { ur.UserId, ur.RoleId }); ;
        builder.Entity<IdentityRoleClaim<Guid>>().ToTable("RoleClaim").HasKey(rc => rc.Id);
        builder.Entity<IdentityUserToken<Guid>>().ToTable("UserToken").HasKey(ut => new { ut.LoginProvider, ut.UserId, ut.Name });
    }

Nothing crazy happening here. Just making the key a Guid and renaming the tables.

Replace appropriate methods to use that User/Role/Key type.

Run, create a user, then go to Two Factor Auth page and you'll hit it on the call to _userManager.GetAuthenticatorKeyAsync(user)

Hi
After the upgrade to Core 2.0 I'm having this issue, please help.
InvalidOperationException: The entity type 'IdentityUserLogin' requires a primary key to be defined.

Regards

May I know the reason why navigation properties were removed from the base pocos??
Beacuse I just know how to use it, then upgrade to .net core 2.0 there are lot of things need to fix... thanks

I changed a lot of content in identity 1.0, I'm very tired when migrations to 2.0 ,I think this is a design mistake of identity

Hi
After three attempts to "migrate" to Core 2 with many errors, I decided to create a new Core 2 project and copy paste my code. I had to do a lot of changes but not errors right now.

Hi,

I tried as described... well everywhere! Seems I'm missing something, I have roles and users to add (ApplicationUser: IdentityUser & ApplicationRole: IdentityRole) in addition to the navigation properties in Application User I also added navigation in ApplicationRole but I get

ApplicationUser does not contain a definition for RoleId.

I can remove that section and it will build but I cant do things such as get all roles and include users, which is needed for my role management system. the folder structure looks ok to me, FK's look a bit off (duplicate keys) as mentioned by others, yet still functional. I can see that the many to many (Roles => Users) isn't working despite working the other way, I just cant seem to fix it! Any help would be appreciated 馃憤

ApplicationRole:
```
public class ApplicationRole : IdentityRole
{
public virtual ICollection Claims { get; set; } = new List();
public virtual ICollection Users { get; set; } = new List();

public ApplicationRole()
{

}

public ApplicationRole(string roleName)
{

}
public ApplicationRole(string roleName, string description)
{
  Description = description;
}

public string Description { get; set; }

}

 Here is my ApplicationUser:

public class ApplicationUser : IdentityUser
{
public virtual string FriendlyName
{
get
{
string friendlyName = string.IsNullOrWhiteSpace(FullName) ? UserName : FullName;

    if (!string.IsNullOrWhiteSpace(JobTitle))
      friendlyName = JobTitle + " " + friendlyName;

    return friendlyName;
  }
}


public string JobTitle { get; set; }
public string FullName { get; set; }
public string Configuration { get; set; }
public bool IsEnabled { get; set; }
public bool IsLockedOut => this.LockoutEnabled && this.LockoutEnd >= DateTimeOffset.UtcNow;

public virtual ICollection<IdentityUserRole<string>> Roles { get; } = new List<IdentityUserRole<string>>();

public virtual ICollection<IdentityUserClaim<string>> Claims { get; } = new List<IdentityUserClaim<string>>();

public virtual ICollection<IdentityUserLogin<string>> Logins { get; } = new List<IdentityUserLogin<string>>();

}

And in my DbContext:

public class SpaDbContext : IdentityDbContext
{
public SpaDbContext(DbContextOptions options)
: base(options)
{
//Database.EnsureCreated();
}

    //List of DB Models - Add your DB models here
    public DbSet<Customer> Customers { get; set; }
    public DbSet<Product> Product { get; set; }
    public virtual DbSet<OpenIddictApplication> OpenIddictApplication { get; set; }
    public virtual DbSet<OpenIddictAuthorization> OpenIddictAuthorization { get; set; }
    public virtual DbSet<OpenIddictScope> OpenIddictScope { get; set; }
    public virtual DbSet<OpenIddictToken> OpenIddictToken { get; set; }

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
  base.OnModelCreating(modelBuilder);
  modelBuilder.UseOpenIddict();
  modelBuilder.Entity<Product>()
      .Property(b => b.EntryTime)
      .HasDefaultValueSql("getdate()");
  modelBuilder.Entity<Customer>().Property(c => c.Name).IsRequired().HasMaxLength(100);
  modelBuilder.Entity<Customer>().HasIndex(c => c.Name);
  modelBuilder.Entity<Customer>().Property(c => c.Email).HasMaxLength(100);
  modelBuilder.Entity<Customer>().Property(c => c.PhoneNumber).IsUnicode(false).HasMaxLength(30);
  modelBuilder.Entity<Customer>().Property(c => c.City).HasMaxLength(50);
  modelBuilder.Entity<Customer>().ToTable($"App{nameof(this.Customers)}");


  modelBuilder.Entity<ApplicationRoleClaim>()
      .HasOne(pt => pt.ApplicationRole)
      .WithMany(t => t.Claims)
      .HasForeignKey(pt => pt.RoleId);
  modelBuilder.Entity<ApplicationUser>()
      .HasMany(e => e.Claims)
      .WithOne()
      .HasForeignKey(e => e.UserId)
      .IsRequired()
      .OnDelete(DeleteBehavior.Cascade);

  modelBuilder.Entity<ApplicationUser>()
      .HasMany(e => e.Logins)
      .WithOne()
      .HasForeignKey(e => e.UserId)
      .IsRequired()
      .OnDelete(DeleteBehavior.Cascade);

  modelBuilder.Entity<ApplicationUser>()
      .HasMany(e => e.Roles)
      .WithOne()
      .HasForeignKey(e => e.UserId)
      .IsRequired()
      .OnDelete(DeleteBehavior.Cascade);
  //mine

  modelBuilder.Entity<ApplicationRole>()
       .HasMany(e => e.Claims)
       .WithOne()
       .HasForeignKey(e => e.RoleId)
       .IsRequired()
       .OnDelete(DeleteBehavior.Cascade);


  modelBuilder.Entity<ApplicationRole>()
      .HasMany(e => e.Users)
      .WithOne()
      .HasForeignKey(x => x.RoleId)
      .OnDelete(DeleteBehavior.Cascade);

}

}
```

fixed it!

Changed my nav properties to match:
applicationuser:

    public virtual ICollection<IdentityUserRole<string>> Roles { get; set; }


    public virtual ICollection<IdentityUserClaim<string>> Claims { get; set; }

ApplicationRole:

    public virtual ICollection<IdentityUserRole<string>> Users { get; set; }

    public virtual ICollection<IdentityRoleClaim<string>> Claims { get; set; }

updated my DbContext:

      modelBuilder.Entity<ApplicationUser>().HasMany(u => u.Claims).WithOne().HasForeignKey(c => c.UserId).IsRequired().OnDelete(DeleteBehavior.Cascade);
      modelBuilder.Entity<ApplicationUser>().HasMany(u => u.Roles).WithOne().HasForeignKey(r => r.UserId).IsRequired().OnDelete(DeleteBehavior.Cascade);

      modelBuilder.Entity<ApplicationRole>().HasMany(r => r.Claims).WithOne().HasForeignKey(c => c.RoleId).IsRequired().OnDelete(DeleteBehavior.Cascade);
      modelBuilder.Entity<ApplicationRole>().HasMany(r => r.Users).WithOne().HasForeignKey(r => r.RoleId).IsRequired().OnDelete(DeleteBehavior.Cascade);

Ensured the initial migration looked ok. and it all worked.

I followed the guide to update Identity in .NET Core 2.0 (https://docs.microsoft.com/en-us/aspnet/core/migration/1x-to-2x/identity-2x) but I get this error:

InvalidOperationException: The entity type 'IdentityUserLogin<int>' requires a primary key to be defined. Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.ValidateNonNullPrimaryKeys(IModel model) Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.Validate(IModel model) Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidator.Validate(IModel model) Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.CreateModel(DbContext context, IConventionSetBuilder conventionSetBuilder, IModelValidator validator) Microsoft.EntityFrameworkCore.Infrastructure.ModelSource+<>c__DisplayClass5_0.<GetModel>b__0(object k) System.Collections.Concurrent.ConcurrentDictionary.GetOrAdd(TKey key, Func<TKey, TValue> valueFactory) Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.GetModel(DbContext context, IConventionSetBuilder conventionSetBuilder, IModelValidator validator) Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel() Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model() Microsoft.EntityFrameworkCore.Infrastructure.EntityFrameworkServicesBuilder+<>c.<TryAddCoreServices>b__7_1(IServiceProvider p) Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, ServiceProvider provider) Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor.VisitCallSite(IServiceCallSite callSite, TArgument argument) Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProvider provider) Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor.VisitCallSite(IServiceCallSite callSite, TArgument argument) Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, ServiceProvider provider) Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor.VisitCallSite(IServiceCallSite callSite, TArgument argument) Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped(ScopedCallSite scopedCallSite, ServiceProvider provider) Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor.VisitCallSite(IServiceCallSite callSite, TArgument argument) Microsoft.Extensions.DependencyInjection.ServiceProvider+<>c__DisplayClass22_0.<RealizeService>b__0(ServiceProvider provider) Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType) Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType) Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService<T>(IServiceProvider provider) Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies() Microsoft.EntityFrameworkCore.DbContext.get_InternalServiceProvider() Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies() Microsoft.EntityFrameworkCore.DbContext.get_Model() Microsoft.EntityFrameworkCore.Internal.InternalDbSet.get_EntityType() Microsoft.EntityFrameworkCore.Internal.InternalDbSet.get_EntityQueryable() Microsoft.EntityFrameworkCore.Internal.InternalDbSet.Microsoft.EntityFrameworkCore.Query.Internal.IAsyncEnumerableAccessor<TEntity>.get_AsyncEnumerable() Microsoft.EntityFrameworkCore.Extensions.Internal.QueryableExtensions.AsAsyncEnumerable<TSource>(IQueryable<TSource> source) Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync<TSource>(IQueryable<TSource> source, CancellationToken cancellationToken)

If I add this to the OnModelCreating
builder.Entity<IdentityUserLogin<int>>().HasKey(p => new { p.UserId });
It complains about IdentityUserRole. I then add this to the same place:
builder.Entity<IdentityUserRole<int>>().HasKey(p => new { p.UserId, p.RoleId });

It complains about the IdentityUserClaims
The relationship from 'IdentityUserClaim<int>' to 'ApplicationUser.Claims' with foreign key properties {'UserId' : int} cannot target the primary key {'Id' : string} because it is not compatible. Configure a principal key or a set of compatible foreign key properties for this relationship.

I do not understand...

@andrenpt I had the same issue and I didn't find anything to help me on Internet. So the thing I did was create a new Core 2.0 empty project and copy paste my code from my old project. It was quicker than search for a solution on Internet. Good luck.

When I try to follow this and just want the Roles Nav Prop added to the user, I get a migration trying to get me to add another UserID foreign key to the User Roles table. Can anyone tell me what I'm doing wrong?

User class:

    public class ApplicationUser : IdentityUser
    {
        // other props omitted
        public virtual ICollection<ApplicationUserRole> Roles { get; } = new List<ApplicationUserRole>();
    }

User Config class:

    public class ApplicationUserConfig : IEntityTypeConfiguration<ApplicationUser>
    {
        public void Configure(EntityTypeBuilder<ApplicationUser> builder)
        {
            builder.ToTable("Users");

            builder.HasMany(e => e.Roles)
                .WithOne()
                .HasForeignKey(e => e.UserId)
                .IsRequired()
                .OnDelete(DeleteBehavior.Cascade);
        }
    }

UserRole class

    public class ApplicationUserRole : IdentityUserRole<string>
    {
    }

Thanks

Turns out my issue had to do with overriding all the strings from nvarchar to varchar (because DBA's).

Not quite sure why Identity doesn't like this and was forcing me to create another User ID property on the User Roles table.

            foreach (var pb in builder.Model
                .GetEntityTypes()
                .SelectMany(t => t.GetProperties())
                .Where(p => p.ClrType == typeof(string))
                .Select(p => builder.Entity(p.DeclaringEntityType.ClrType).Property(p.Name)))
            {
                pb.IsUnicode(false);
            }

@ajcvickers See the 2 comments from @scottsauber 鈽濓笍. Is this expected behavior?

@scottaddie Not as described. However, I believe that the migration shipped with the 2.0.x release does not have an entry for the FK that it should have, which means that it will be added when the first new migration is added--this might be a symptom of that. It's on my list to figure out what to do for 2.1 to fix several related issues around the way Identity is defining its model and using Migrations.

@mattgross76

It looks like the problem occurs when attempting to serialize the System.Security.Claims.ClaimsPrincipal class. I don't see any release notes regarding changes to this class, so it is difficult to figure out what is happening.

Anyone else seeing something similar? This is the only issue I have with Core 2.0.

I faced the same issue. Have you found a solution?

Hello I am following a tutorial on udemy and instructor was explaining the identity. He added the same in the tutorial and i am getting some error when i am trying to add this. Can someone help me out ? I am attaching all the relevant information i can about my project and error.

Screenshot of error which i am getting in browser.
image

Screenshot of my startup.cs file
image

Screenshot of my Application User File:
image

can anyone help me out if i am missing any file or missing lines of code ?

@H4Himanshu
When you do services.AddIdentity<ApplicationUser, IdentityRole>() , first generic argument is the User type and second is the Role. Your _ApplicationRole_ class should inherit from _IdentityRole_ and _Customer_ class should inherit from _IdentityUser_.

You can check out the docs to get familiar with basics of ASP.NET Identity.

@HaoK
I just migrated from 1.x to 2.x and I'm trying to follow your directions, regarding configuration for the Role Poco properties in the DBContext configuration, but I don't see where IdentityUserRole ever has a .Users property. Here is my setup, perhaps you can tell me what's wrong:

ApplicationUser:

 public partial class ApplicationUser : IdentityUser<string>
    {
        public ApplicationUser()
        {}
        public virtual ICollection<IdentityUserRole<string>> Roles { get; } = new 
 List<IdentityUserRole<string>>();

}

ApplicationDbContext:

  public class ApplicationDbContext : IdentityDbContext<ApplicationUser, MyApplicationRole, string>
    {
        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
        {
        }

        modelBuilder.Entity<ApplicationUser>()
                .HasMany(e => e.Roles)
                .WithOne()
                .HasForeignKey(e => e.UserId)
                .IsRequired()
                .OnDelete(DeleteBehavior.Cascade);

            modelBuilder.Entity<IdentityUserRole<string>>()
                .HasMany(e => e.Users)  // <-- No such property
                .WithOne()
                .HasForeignKey(e => e.RoleId)
                .IsRequired()
                .OnDelete(DeleteBehavior.Cascade);
}

roles2

Here is the database view:
roles1

roles3

Thanks in advance for any info you can provide!

I'm migrating an MVC6 application to .NET Core. All I want to do is:

context.Users.Include(u=>u.UserRoles).ThenInclude(ur => ur.Roles)

That's it, nothing fancy. I tried adding the nav properties per inheriting from IdentityUser, IdentityUserRole, and IdentityRole and it complains about not having a primary key for IdentityUserRole. Add a primary key to the builder and it complains that it's already being used (probably in base.onmodelcreating()).

After 3 hours I've decided my time is more valuable and I'll just write a SQL query. This should not be a hard thing to solve folks.

I am facing with the same problem

The relationship from 'IdentityUserClaim<int>' to 'ApplicationUser.Claims' with foreign key properties {'UserId' : int} cannot target the primary key {'Id' : string} because it is not compatible. Configure a principal key or a set of compatible foreign key properties for this relationship. Any solution for this? In my case it is not IdentityUserClaim but IdentityUserRole.

@Aleksaas you must specific your id in int type not Guid

@HaoK @mattgross76
I have the same problem: https://github.com/aspnet/Identity/issues/1364#issuecomment-323767718

We periodically close 'discussion' issues that have not been updated in a long period of time.

We apologize if this causes any inconvenience. We ask that if you are still encountering an issue, please log a new issue with updated information and we will investigate.

Was this page helpful?
0 / 5 - 0 ratings