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

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)

[Nest.js] Use WebSocket with ws

Intro Until last time , I had used node-web-rtc to try WebRTC. But because the example was a little complicated for I understood the core functions of using WebRTC. So I look for other frameworks or libraries. PeerJS is a famous library for WebRTC. peers/peerjs: Peer-to-peer data in the browser. - GitHub peers/peerjs-server: Server for PeerJS - GitHub PeerJS - Simple peer-to-peer with WebRTC A problem is I don't know how to integrate to the Nest.js project. I couldn't find examples. So I don't choose at least this time. What shall I choose? According MDN, WebRTC doesn't specify strictly what technology is used on server application for connecting two devices. Signaling and video calling - Web APIs | MDN But in many examples include MDN's one use WebSocket. samples-server/s/webrtc-from-chat at master · mdn/samples-server · GitHub So I try WebSocket in the Nest.js project. Use WebSocket in a Nest.js project Nest.js has a function for using We

[Nest.js] Show static files

Intro I wanted to use Nest.js and WebRTC(node-webrtc). NestJS - A progressive Node.js framework Documentation | NestJS - A progressive Node.js framework And because I wanted to try with simple page(not use JavaScript frameworks), I added static HTML, CSS, JavaScript into a Nest.js project. Prepare Install First, I installed @nestjs/cli. First steps | NestJS - A progressive Node.js framework As same as last time , I couldn't do global install because I had used Volta. But I could installed by volta. volta install @nestjs/cli Create project nest new nest-web-rtc-sample volta pin node@12 Run npm start After doing "npm start", I could getting "Hello World!" from http://localhost:3000. Add static files I could add static files by two ways. @nestjs/serve-static First one of them was using "serve-static". Serve Static | NestJS - A progressive Node.js framework npm install --save @nestjs/serve-static And I needed adding a module into app.modu