[ASP.NET Core][EntityFramework Core] Update from .NET 5 to .NET 6

masanori_msl

Masui Masanori

Posted on December 6, 2021

[ASP.NET Core][EntityFramework Core] Update from .NET 5 to .NET 6

Intro

Congratulations on the release of .NET 6 !
I want to update ASP.NET Core projects what are made in .NET 5 to .NET 6.

Environments

  • .NET ver.5.0.202 -> .NET ver.6.0.100

Sample project

I use a project what I created for trying signing in from Blazor pages.

ApprovementWorkflowSample.csproj

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>net5.0</TargetFramework>
    <Nullable>enable</Nullable>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="NLog.Web.AspNetCore" Version="4.10.0"/>
    <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="5.0.2"/>
    <PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.2"/>
    <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.2"/>
    <PackageReference Include="Newtonsoft.Json" Version="12.0.3"/>
    <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.2"/>
    <PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="5.0.2"/>
  </ItemGroup>
</Project>
Enter fullscreen mode Exit fullscreen mode

Program.cs

using System;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using NLog.Web;

namespace ApprovementWorkflowSample
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var logger = NLogBuilder.ConfigureNLog("Nlog.config").GetCurrentClassLogger();
            try 
            {
                CreateHostBuilder(args).Build().Run();
            }
            catch (Exception ex) {
                logger.Error(ex, "Stopped program because of exception");
                throw;
            }
            finally {
                NLog.LogManager.Shutdown();
            }
        }
        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                })
                .ConfigureLogging((hostingContext, logging) =>
                {
                    logging.ClearProviders();
                    logging.SetMinimumLevel(LogLevel.Trace);
                })
                .UseNLog();
    }
}
Enter fullscreen mode Exit fullscreen mode

Startup.cs

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using ApprovementWorkflowSample.Applications;
using ApprovementWorkflowSample.Models;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Server;
using ApprovementWorkflowSample.Approvements;

namespace ApprovementWorkflowSample
{
    public class Startup
    {
        private readonly IConfiguration configuration;
        public Startup(IConfiguration configuration)
        {
            this.configuration = configuration;
        }
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddRazorPages();
            services.AddServerSideBlazor();
            services.AddHttpClient();

            services.AddControllers()
                .AddNewtonsoftJson();
            services.AddDbContext<ApprovementWorkflowContext>(options =>
                options.UseNpgsql(configuration["DbConnection"]));
            services.AddIdentity<ApplicationUser, IdentityRole<int>>()
                .AddUserStore<ApplicationUserStore>()
                .AddEntityFrameworkStores<ApprovementWorkflowContext>()
                .AddDefaultTokenProviders();
            services.AddScoped<IHostEnvironmentAuthenticationStateProvider>(sp =>
                (ServerAuthenticationStateProvider) sp.GetRequiredService<AuthenticationStateProvider>()
            );
            services.AddScoped<IApplicationUsers, ApplicationUsers>();
            services.AddScoped<IWorkflows, Workflows>();
            services.AddScoped<IApplicationUserService, ApplicationUserService>();
            services.AddScoped<IApprovementService, ApprovementService>();
        }
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            app.UseStaticFiles();
            app.UseRouting();
            app.UseAuthentication();
            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapBlazorHub();
                endpoints.MapControllers();
            });
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Update to .NET 6

To update the project to .NET 6, I change "ApprovementWorkflowSample.csproj" first.

ApprovementWorkflowSample.csproj

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="NLog.Web.AspNetCore" Version="4.14.0"/>
    <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="6.0.1"/>
    <PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.0"/>
    <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.0"/>
    <PackageReference Include="Newtonsoft.Json" Version="13.0.1"/>
    <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.0"/>
    <PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="6.0.0"/>
  </ItemGroup>
</Project>
Enter fullscreen mode Exit fullscreen mode

Before .NET 5 or earlier, I had had to changed some code after restoring.
But in this time, I don't need to change anything.

Merge "Startup.cs" into "Program.cs"

If I create a new .NET 6 project, it doesn't have "Startup.cs" and "Program.cs" doesn't have a class.

Program.cs (mvc template)

var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
Enter fullscreen mode Exit fullscreen mode

Program.cs

using ApprovementWorkflowSample.Models;
using ApprovementWorkflowSample.Applications;
using ApprovementWorkflowSample.Approvements;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Server;
using NLog.Web;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;

var logger = NLogBuilder.ConfigureNLog("Nlog.config").GetCurrentClassLogger();
try 
{
    var builder = WebApplication.CreateBuilder(args);
    builder.Host.ConfigureLogging(logging =>
    {
        logging.ClearProviders();
        logging.AddConsole();
    })
    .UseNLog();
    builder.Services.AddRazorPages();
    builder.Services.AddServerSideBlazor();
    builder.Services.AddHttpClient();
    builder.Services.AddControllers()
                .AddNewtonsoftJson();
    builder.Services.AddDbContext<ApprovementWorkflowContext>(options =>
                options.UseNpgsql(builder.Configuration["DbConnection"]));
    builder.Services.AddIdentity<ApplicationUser, IdentityRole<int>>()
                .AddUserStore<ApplicationUserStore>()
                .AddEntityFrameworkStores<ApprovementWorkflowContext>()
                .AddDefaultTokenProviders();
    builder.Services.AddScoped<IHostEnvironmentAuthenticationStateProvider>(sp =>
                (ServerAuthenticationStateProvider) sp.GetRequiredService<AuthenticationStateProvider>()
            );
    builder.Services.AddScoped<IApplicationUsers, ApplicationUsers>();
    builder.Services.AddScoped<IWorkflows, Workflows>();
    builder.Services.AddScoped<IApplicationUserService, ApplicationUserService>();
    builder.Services.AddScoped<IApprovementService, ApprovementService>();
    // I can't do this before setting "WebApplicationBuilder".
    var app = builder.Build();
    if (app.Environment.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }    
    app.UseStaticFiles();
    app.UseRouting();
    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapBlazorHub();
        endpoints.MapControllers();
    });
    app.Run();
}
catch (Exception ex) {
    logger.Error(ex, "Stopped program because of exception");
}
finally {
    NLog.LogManager.Shutdown();
}
Enter fullscreen mode Exit fullscreen mode

DateTime (EntityFramework Core + Npgsql)

From .NET 6, the data types of date and time have been changed.

And I got an exception when I insert data.

ApplicationUser.cs

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.AspNetCore.Identity;

namespace ApprovementWorkflowSample.Applications
{
    public class ApplicationUser: IdentityUser<int>
    {
...
        [Required]
        [Column("last_update_date", TypeName = "timestamp with time zone")]
        public DateTime LastUpdateDate { get; set; }
...
        public void Update(string userName, string? organization,
            string email, string password)
        {
            UserName = userName;
            Organization = organization;
            Email = email;
            // set hashed password text to PasswordHash.
            PasswordHash = new PasswordHasher<ApplicationUser>()
                .HashPassword(this, password);
            // Get error
            LastUpdateDate = DateTime.Now;
        }
...
    }
}
Enter fullscreen mode Exit fullscreen mode

Error

InvalidCastException: Cannot write DateTime with Kind=Local to PostgreSQL type 'timestamp with time zone', only UTC is supported. Note that it's not possible to mix DateTimes with different Kinds in an array/range. See the Npgsql.EnableLegacyTimestampBehavior AppContext switch to enable legacy behavior.
Enter fullscreen mode Exit fullscreen mode

So I had to convert to Universal time.

ApplicationUser.cs

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.AspNetCore.Identity;

namespace ApprovementWorkflowSample.Applications
{
    public class ApplicationUser: IdentityUser<int>
    {
...
        [Required]
        [Column("last_update_date", TypeName = "timestamp with time zone")]
        public DateTime LastUpdateDate { get; set; }
...
        public void Update(string userName, string? organization,
            string email, string password)
        {
            UserName = userName;
            Organization = organization;
            Email = email;
            // set hashed password text to PasswordHash.
            PasswordHash = new PasswordHasher<ApplicationUser>()
                .HashPassword(this, password);
            // OK
            LastUpdateDate = DateTime.Now.ToUniversalTime();
        }
...
    }
}
Enter fullscreen mode Exit fullscreen mode
💖 💪 🙅 🚩
masanori_msl
Masui Masanori

Posted on December 6, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related