This site uses cookies to deliver our services. By using this site, you acknowledge that you have read and understand our Cookie and Privacy policy. Your use of Kontext website is subject to this policy. Allow Cookies and Dismiss

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

871 views 2 comments last modified about 10 months ago Raymond

In this page

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.

Related pages

Issue - Unable to get property 'apply' of undefined or null reference occurred in Angular 4.*, VS2017 15.3, ASP.NET Core 2.0

6133 views   10 comments last modified about 2 years ago

Issue Context After installed Visual Studio 2017 15.3 preview and .net core 2.0 preview SDK, I upgraded one of my existing asp.net core project to 2.0. The project was created using ‘dotnet new angular’ SPA template.&nbsp; I also upgraded all the client app packages to the latest. For exa...

View detail

Tuples in C# (4.x, 7.0, 7.1)

86 views   0 comments last modified about 4 months ago

What is a tuple? Tuple is an ordered sequence, fixed-size, immutable and of heterogeneous objects. Tuple has been existing in other languages such as F#, Python, Perl and etc. for a long time. It was first introduced into C# from C# 4.0 and has been evolving over time. Since C# 7.1, tuple...

View detail

Invoke Hadoop WebHDFS APIs in .NET Core

139 views   0 comments last modified about 4 months ago

Background Apache doesn't provide native official .NET APIs for Hadoop HDFS. The HTTP REST API supports the complete FileSystem / ...

View detail

Logging configuration in .NET core

258 views   0 comments last modified about 9 months ago

.NET core introduces a logging API that works with a number of logging frameworks. The built-in providers are configurable and extensible to support different level loggings.

View detail

Sending Emails in .NET Core Applications

1199 views   0 comments last modified about 9 months ago

Sending emails are common in applications. For example, when user registers, we need to send account activation emails. This post summarize the approaches we can use to send emails in .NET Core 1.x and 2.x.

View detail

Retrieve Http client request metadata like IP address and languages in asp.net core

805 views   0 comments last modified about 9 months ago

IP Address In ASP.NET Core, Request.UserHostAddress has been removed though that attribute exists in the traditional ASP.NET applications. We can use HttpContext.Connection to retrieve the remove client IP address: var ipAddress = HttpContext.Connecti...

View detail

Add comment

Please login first to add comments.  Log in New user?  Register

Comments (2)

R Re: Migrating from ASP.NET Core 1.x to ASP.NET Core 2.0

Ra*** about 9 months ago

@Michael

https://github.com/aspnet/Identity/blob/dev/src/Microsoft.Extensions.Identity.Core/RoleManager.cs

The default query doesn’t include property Users as it is extended by us. Thus, you can write your own Linq query to use entity framework core extension method Include(r=>r.Users) to ensure Users are also loaded.

 In this way, the query generated will be a join SQL.


Mi*** about 9 months ago

Hello, I've followed your suggestions above but still can't get out how many users that are assigned to a Role. I get: System.Data.SqlClient.SqlException: 'Invalid column name 'ApplicationRoleId'.' when I'm executing following: model = roleManager.Roles.Select(r => new ApplicationRoleListViewModel { Id = r.Id, Name = r.Name, NumberOfUsers = r.Users.Count() }).ToList(); Do you have some ideas on what I have done wrong? Thanks, Michael.
M Re:Migrating from ASP.NET Core 1.x to ASP.NET Core 2.0

Mi*** about 9 months ago

Hello, I've followed your suggestions above but still can't get out how many users that are assigned to a Role. I get: System.Data.SqlClient.SqlException: 'Invalid column name 'ApplicationRoleId'.' when I'm executing following: model = roleManager.Roles.Select(r => new ApplicationRoleListViewModel { Id = r.Id, Name = r.Name, NumberOfUsers = r.Users.Count() }).ToList(); Do you have some ideas on what I have done wrong? Thanks, Michael.