スキップしてメイン コンテンツに移動

Upgrade from ASP.NET Core 2.2 to 3.0

Conguratulations on the releasing .NET Core 3.0 and ASP.NET Core 3.0!
Today's theme is about upgrading ASP.NET Core from ver.2.2 to ver.3.0.

What I did

  1. Creating an empty ASP.NET Core project(ver.2.2.402)
  2. Adding EntityFrameworkCore by NuGet
  3. Adding some codes
  4. Upgrading to ver.3.0.100
  5. Fixing some problems

Setup

Environments

  • .NET Core : ver.2.2.402, ver.3.0.100
  • Microsoft.EntityFrameworkCore : ver.2.2.6, ver.3.0.0
  • Npgsql.EntityFrameworkCore.PostgreSQL : ver.2.2.4, ver.3.0.1
  • Windows10 : ver.1903
  • Rider : ver.2019.2.3
  • PostgreSQL : ver.12.0

Creating the base project

UpgradeSample.csproj

<Project Sdk="Microsoft.NET.Sdk.Web">

    <PropertyGroup>
        <TargetFramework>netcoreapp2.2</TargetFramework>
        <AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
    </PropertyGroup>

    <ItemGroup>
        <PackageReference Include="Microsoft.AspNetCore.App" />
        <PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" />
        <PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.2.6" />
        <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="2.2.4" />
    </ItemGroup>

</Project>

Program.cs

using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;

namespace UpgradeSample
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateWebHostBuilder(args).Build().Run();
        }
        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>();
    }
}

Startup.cs

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

using Newtonsoft.Json.Serialization;
using UpgradeSample.Models;
using UpgradeSample.Products;

namespace UpgradeSample
{
    public class Startup
    {
        private IConfigurationRoot Configuration { get; }

        public Startup(IHostingEnvironment env)
        {
            var builder = new ConfigurationBuilder()
                .SetBasePath(env.ContentRootPath)
                .AddJsonFile("appsettings.json", false, true)
                .AddJsonFile($"appsettings.{env.EnvironmentName}.json", false, true)
                .AddEnvironmentVariables();
            Configuration = builder.Build();
        }
        public void ConfigureServices(IServiceCollection services)
        {
            // DB Connect
            services.AddDbContext<UpgradeSampleContext>(options =>
                options.UseNpgsql(Configuration["DbConnect"]));
            // for setting JSON parameter names pascal case.
            services.AddMvc()
                .AddJsonOptions(options =>
                {
                    options.SerializerSettings.ContractResolver = new DefaultContractResolver();
                });
            // DI
            services.AddScoped<IProductDao, Productdao>();
            services.AddScoped<IProductService, ProductService>();
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            app.UseStaticFiles();
            app.UseMvc();
        }
    }
}

For routing

ApiController.cs

using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using UpgradeSample.Models;
using UpgradeSample.Products;

namespace UpgradeSample.Controllers
{
    public class ApiController: Controller
    {
        private readonly IProductService _productService;
        public ApiController(IProductService productService)
        {
            _productService = productService;
        }
        [Route("/")]
        [Route("/Home")]
        public string Index()
        {
            return "hello";
        }
        [HttpGet]
        [Route("/products")]
        public async Task<List<Product>> GetProducts()
        {
            return await _productService.GetProductsAsync();
        }
    }
}

For DB accessing

UpgradeSampleContext.cs

using Microsoft.EntityFrameworkCore;

namespace UpgradeSample.Models
{
    public class UpgradeSampleContext: DbContext
    {
        public UpgradeSampleContext(DbContextOptions<UpgradeSampleContext> options)
            :base(options)
        {
        }
        public DbSet<Product> Products { get; set; }
    }
}

Product.cs

using System.ComponentModel.DataAnnotations.Schema;

namespace UpgradeSample.Models
{
    [Table("Product")]
    public class Product
    {
        [Column("ProductId")]
        public int? ProductId { get; set; }
        [Column("ProductName")]
        public string ProductName { get; set; }
    }
}

IProductService.cs

using System.Collections.Generic;
using System.Threading.Tasks;
using UpgradeSample.Models;

namespace UpgradeSample.Products
{
    public interface IProductService
    {
        Task<List<Product>> GetProductsAsync();
    }
}

ProductService.cs

using System.Collections.Generic;
using System.Threading.Tasks;
using UpgradeSample.Models;

namespace UpgradeSample.Products
{
    public class ProductService: IProductService
    {
        private readonly IProductDao _productDao;
        public ProductService(IProductDao productDao)
        {
            _productDao = productDao;
        }
        public async Task<List<Product>> GetProductsAsync()
        {
            return await _productDao.GetProductsAsync();
        }
    }
}

IProductDao.cs

using System.Collections.Generic;
using System.Threading.Tasks;
using UpgradeSample.Models;

namespace UpgradeSample.Products
{
    public interface IProductDao
    {
        Task<List<Product>> GetProductsAsync();
    }
}

ProductDao.cs

using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using UpgradeSample.Models;

namespace UpgradeSample.Products
{
    public class ProductDao: IProductDao
    {
        private readonly UpgradeSampleContext _context;
        public ProductDao(UpgradeSampleContext context)
        {
            _context = context;
        }
        public async Task<List<Product>> GetProductsAsync()
        {
            return await _context.Products.ToListAsync();
        }
    }
}

DB

SQL


CREATE TABLE "Product"(
 "ProductId" serial PRIMARY KEY,
 "ProductName" text NOT NULL
);
INSERT INTO "Product"(
 "ProductName"
)
VALUES
(
 'Nykee Running Shoes'
);
INSERT INTO "Product"(
 "ProductName"
)
VALUES
(
 'South Face Jacket'
);


Upgrade to ver.3.0.100

I changed 2 files and restored.

global.json

{
  "sdk": {
    "version": "3.0.100"
  }
}

UpgradeSample.csproj

<Project Sdk="Microsoft.NET.Sdk.Web">
    <PropertyGroup>
        <TargetFramework>netcoreapp3.0</TargetFramework>
    </PropertyGroup>
    <ItemGroup>
        <PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.0.0" />
        <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="3.0.1" />
    </ItemGroup>
</Project>

Fix problems

After upgrading, I found 3 warnings.

Startup.cs(15, 24): [CS0618] 'IHostingEnvironment'is obsolete ('This type is obsolete and will be removed in a future version. The recommended alternative is Microsoft.AspNetCore.Hosting.IWebHostEnvironment.')
Startup.cs(35, 56): [CS0618] 'IHostingEnvironment'is obsolete ('This type is obsolete and will be removed in a future version. The recommended alternative is Microsoft.AspNetCore.Hosting.IWebHostEnvironment.')
Startup.cs(42, 13): [MVC1005] Using 'UseMvc' to configure MVC is not supported while using Endpoint Routing. To continue using 'UseMvc', please set 'MvcOptions.EnableEndpointRouting = false' inside 'ConfigureServices'.

IHostingEnvironment and UseMvc had been changed.(Thank you for teaching me alternatives:) )
I changed only one class, Startup.cs.

Startup.cs


using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using UpgradeSample.Models;
using UpgradeSample.Products;

namespace UpgradeSample
{
    public class Startup
    {
        private IConfigurationRoot Configuration { get; }
        public Startup(IHostingEnvironment env)
        {
            var builder = new ConfigurationBuilder()
                .SetBasePath(env.ContentRootPath)
                .AddJsonFile("appsettings.json", false, true)
                .AddJsonFile($"appsettings.{env.EnvironmentName}.json", false, true)
                .AddEnvironmentVariables();
            Configuration = builder.Build();
        }
        public void ConfigureServices(IServiceCollection services)
        {
            // DB Connect
            services.AddDbContext<UpgradeSampleContext>(options =>
                options.UseNpgsql(Configuration["DbConnect"]));
            
            // for setting JSON parameter names pascal case.
            services.AddControllers()
                .AddJsonOptions(options =>
                    options.JsonSerializerOptions.PropertyNamingPolicy = null);
                    
            // DI
            services.AddScoped<IProductDao, Productdao>();
            services.AddScoped<IProductService, ProductService>();
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            app.UseStaticFiles();
            
            app.UseRouting();
            app.UseEndpoints(endpoints =>
            {
                // for attribute-routing.
                endpoints.MapControllers();
            });
        }
    }
}


Endpoint Routing

I thought the main reason of this change was caused by using Endpoint Routing.

It separated middleware systems(for example MVC, Razor Pages, etc.) like below code.

Startup.cs


        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
            services.AddRazorPages();
        }


Furthermore, it separated routing from endpoint.

Startup.cs


        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            app.UseRouting();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }


UseEndpoints required routing.

So this caused an exception.

Startup.cs


        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            // Exception was occurred at the runtime.
            // app.UseRouting(); 

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }


But if there ware no endpoints, no exceptions were occurred and the white page was shown;P.

Next time, I will try login/logout by ASP.NET Core Identity.

Resources

コメント

このブログの人気の投稿

[Angular][ASP.NET Core] Upload chunked files

Intro I wanted to send files to Web application (made by ASP.NET Core). If the file size had been small, I didn't need do any special things. But when I tried to send a large file, the error was occurred by ASP.NET Core's limitation. Though I could change the settings, but I didn't want to do that, because I hadn't known the file sizes what would been actually using. So I splitted the data into chunks first, and sent them. After receiving all chunks, I merged them into one file. There might be some libraries or APIs (ex. Stream API) what did them automatically, but I couldn't find them. What I did [ASP.NET Core] Make CORS enabled [Angular] Split a large file into chunks [Angular][ASP.NET Core] Send and receive data as form data [ASP.NET Core] Merge chunks into one file [ASP.NET Core] Make CORS enabled Because the client side application(Angular) and the server side application(ASP.NET Core) had been separated, I had to make CORS(Cross-Origin Requests) ...

[PostgreSQL] Play with TypeORM 1

Intro This time, I tried accessing Database by TypeORM. Because I wanted to manage Database tables by ORM, I created a table first.  GitHub - typeorm/typeorm   TypeORM - Amazing ORM for TypeScript and JavaScript (ES7, ES6, ES5). Installation and creating a project Installation TypeORM needed "reflect-metadata" and database driver. npm install --save typeorm reflect-metadata pg typescript tsc npm install --save-dev @types/node And I also installed "ts-node" to skip compiling. npm install --save ts-node Preparing References I could generate a TypeORM project by TypeORM command. npx typeorm init --name gen-typeorm-sample --database postgres I refered Most of all settings from it. Adding files and folders First, I added tsconfig.json. npx tsc --init And I edited like below. tsconfig.json { "compilerOptions": { /* Basic Options */ "incremental": true, "target": "es5", "module": "comm...

[Ubuntu] Install Docker, PostgreSQL(From DockerHub), PgAdmin4 + SELECT ALL

Intro I build development of PostgreSQL environment on Ubuntu this time. Because I haven't wanted to install PostgreSQL directly, I use Docker to install it. After installing them, I will try some SQL. Build development environments Docker According to the documents, I add repository and install "docker-ce", "docker-ce-cli", "containerd.io" Get Docker Engine - Community for Ubuntu | Docker Documentation When I had installed "Docker for Windows" on Windows, it had the GUI application. But maybe there is no GUI application for Ubuntu or I need installing another package? PostgreSQL(Docker Hub) Because I have wanted to use latest version, I just do "docker pull postgres". postgres - Docker Hub After getting PostgreSQL, I made mistake when I did "docker run". docker run (failed) docker run --name sample-shop -e POSTGRES_PASSWORD=postgres -d postgres -p 5432:5432 There are no any errors, but I can't access to...