Migrating from ASP.NET Core 1.x to ASP.NET Core 2.0

access_time 4 years ago visibility2308 comment 0

Migrating from ASP.NET Core 1.x to 2.0 is not an easy job especially if you have customized Identity and used customized authentication. This post summarizes the issues and errors I have experienced and their resolutions when upgrading my project. Hopefully it can save you sometime if you are doing the same.

Official Migration Guides

Please refer to the following official posts for general migration strategies and steps:

Migrating from ASP.NET Core 1.x to ASP.NET Core 2.0

Migrating Authentication and Identity to ASP.NET Core 2.0

[Draft] Auth 2.0 Migration announcement

Navigation Properties for IdentityUser<TKey>

Navigation properties: Roles, Claims and Logins have been removed from IdentityUser<TKey> class.

To add them back, you need to create your own user class , for example,

public class ApplicationUser : IdentityUser<int>

And then add the following attributes.

#region  asp.net core 2.0 support

/// <summary>
/// Navigation property for the roles this user belongs to.
/// </summary>
public virtual ICollection<IdentityUserRole<int>> Roles { get; } = new List<IdentityUserRole<int>>();

/// <summary>
/// Navigation property for the claims this user possesses.
/// </summary>
public virtual ICollection<IdentityUserClaim<int>> Claims { get; } = new List<IdentityUserClaim<int>>();

/// <summary>
/// Navigation property for this users login accounts.
/// </summary>
public virtual ICollection<IdentityUserLogin<int>> Logins { get; } = new List<IdentityUserLogin<int>>();

#endregion

To prevent duplicate foreign keys when running EF Core migrations, you can add the following to your IdentityDbContext class:

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

           #region  asp.net core 2.0 support
            builder.Entity<ApplicationUser>()
                .HasMany(e => e.Claims)
                .WithOne()
                .HasForeignKey(e => e.UserId)
                .IsRequired()
                .OnDelete(DeleteBehavior.Cascade);

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

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

            #endregion

Navigation Properties for IdentityRole<TKey>

Similar to the user class, navigation property Claims and Users have also been removed from IdentityRole<TKey> class. To add them back, create a ApplicationRoleClaim class:

public class ApplicationRoleClaim : IdentityRoleClaim<int>
     {
         public virtual ApplicationRole ApplicationRole { get; set; }
     }

Remember to change int to your own primary key type.

In your own customized IdentityRole<TKey> class, add the following code:

public class ApplicationRole : IdentityRole<int>
  {

        #region  asp.net core 2.0 support
         /// <summary>
         /// Navigation property for the users in this role.
         /// </summary>
         public virtual ICollection<IdentityUser<int>> Users { get; } = new List<IdentityUser<int>>();

        /// <summary>
         /// Navigation property for the claims this role possesses.
         /// </summary>
         public virtual ICollection<ApplicationRoleClaim> Claims { get; } = new List<ApplicationRoleClaim>();
         #endregion
     }

And then add the following code into your customized IdentityDbContext to prevent duplicate foreign key:

builder.Entity<ApplicationRoleClaim>()
                 .HasOne(pt => pt.ApplicationRole)
                 .WithMany(t => t.Claims)
                 .HasForeignKey(pt => pt.RoleId);

Error CS0023 Operator '!' cannot be applied to operand of type 'AuthorizationResult'

In one of my API controllers, I got the above error when building my project while it was working well with .net core SDK 1.x.

public async Task<IActionResult> GetUserById(int id)
         {
             if (!await authorizationService.AuthorizeAsync(this.User, id, ApplicationAuthorizationPolicies.ViewUserByUserIdPolicy))
                 return new ChallengeResult();

Change the code to:

if (!(await authorizationService.AuthorizeAsync(this.User, id, ApplicationAuthorizationPolicies.ViewUserByUserIdPolicy)).Succeeded)
                 return new ChallengeResult();

The change is required because in 1.x, IAuthorizationService is defined as:

public interface IAuthorizationService

{

Task<bool> AuthorizeAsync(ClaimsPrincipal user, object resource, IEnumerable<IAuthorizationRequirement> requirements);

Task<bool> AuthorizeAsync(ClaimsPrincipal user, object resource, string policyName);

}

In 2.0. it is changed to:
    public interface IAuthorizationService
    {
        Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, object resource, IEnumerable<IAuthorizationRequirement> requirements);
        Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, object resource, string policyName);
    }

An error occurred while calling method 'BuildWebHost' on class 'Program'. Continuing without the application service provider. Error: One or more errors occurred. (A key cannot be configured on 'ApplicationUser' because it is a derived type. The key must be configured on root type 'IdentityUser<int>'. If you did not intend for 'IdentityUser<int>' 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.

The error itself is self-explaining. I have defined the following attribute in ApplicationRole class:

public virtual ICollection<IdentityUser<int>> Users { get; } = new List<IdentityUser<int>>();

While it should be changed to:

public virtual ICollection<ApplicationUser> Users { get; } = new List<ApplicationUser>();

Options.ClientId must be provided Parameter name: ClientId

Ensure you have configured all the required attributes for OIDC authentication.

services.AddAuthentication(options =>
             {
                 options.DefaultAuthenticateScheme = OpenIdConnectDefaults.AuthenticationScheme;
                 options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
                 options.DefaultSignInScheme = OpenIdConnectDefaults.AuthenticationScheme;
             }).AddOpenIdConnect(options =>
             {
                 options.Authority = Configuration["auth:oidc:authority"];
                 options.ClientId = Configuration["auth:oidc:clientid"];

                 options.SaveTokens = true;
                 // for development, disable https requirement
                 options.RequireHttpsMetadata = false;
             });

If you have experienced more issues, please post here and we can discuss and resolve together.

info Last modified by Administrator at 5 days ago copyright This page is subject to Site terms.
Like this article?
Share on

Please log in or register to comment.

account_circle Log in person_add Register

Log in with external accounts

Want to publish your article on Kontext?

Learn more

Kontext Column

Created for everyone to publish data, programming and cloud related articles.
Follow three steps to create your columns.


Learn more arrow_forward

More from Kontext

local_offer dotnetcore

visibility 3312
thumb_up 0
access_time 3 years ago

.NET Framework, you can use |DataDirectory| to configure connection string when connecting to SQL Server database file via attach mode: AttachDbFilename=|DataDirectory|\dbname.mdf In .NET Core, you cannot directly set SQL Server Express connection string by using any tokens directly. There is ...

local_offer asp.net core 2 local_offer dotnetcore

visibility 2751
thumb_up 0
access_time 3 years ago

In .NET Core 2.x, Windows Forms or WPF are not implemented since they are based on GDI+ and DirectX respectively in Windows. In .NET Core 3.0, there is plan to add Desktop Packs which includes UWP. WPF and Windows Forms. However, they will still be Windows-only. In .NET Core applications, you may ...

local_offer asp.net core 2 local_offer asp.net core

visibility 1153
thumb_up 0
access_time 4 years ago

Other related issues are found during my migration. https://stackoverflow.com/questions/46118930/unable-to-change-asp-identity-table-names-asp-net-core-2 I faced the same issue as the above post. To fix it, I need to derive my database context with all the parameters specified: public ...

About column

Articles about ASP.NET Core 1.x, 2.x and 3.x.

rss_feed Subscribe RSS