1. 程式人生 > >asp.net core 3.0 更新簡記

asp.net core 3.0 更新簡記

asp.net core 3.0 更新簡記

Intro

最近把活動室預約專案從 asp.net core 2.2 更新到了 asp.net core 3.0,記錄一下,升級踩過的坑以及經驗總結,包括但不限於

  • TargetFramework (netcoreapp2.2 需要更新為 netcoreapp3.0)
  • Dependency
  • Host/Environment
  • Mvc
  • Routing
  • Swagger
  • Dockerfile
  • EF(不推薦更新)

TargetFramework 更新

原來專案裡的 netcoreapp2.x 版本需要更新為 netcoreapp3.0,原來有些基於 netstandard2.0 的專案的包如果有包更新之後依賴 netstandard2.1

可能需要更新為 netstandard2.1(非必須,看專案依賴)

Dependency

原來在 dotnetcore 2.x 版本時大部分的包以 nuget 的形式提供,可以直接通過 nuget 引用,從 dotnetcore 3.0 開始很多包不再發布 nuget 包,需要通過框架引用來引用包(FrameworkReference)

比如在一個類庫專案 <Project Sdk="Microsoft.NET.Sdk"> 裡有這麼一個引用 <PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.2" />

,在 dotnetcore 3.0 並沒有釋出對應的 nuget 包,需要使用框架引用,示例如下:

<FrameworkReference Include="Microsoft.AspNetCore.App" />

如果是 Web 專案 <Project Sdk="Microsoft.NET.Sdk.Web">,Sdk 是 Web 的話直接把 targetFramework 更新的 netcoreapp3.0 就可以了,不需要再新增上面的引用了,專案裡 <PackageReference Include="Microsoft.AspNetCore.App"/>

的引用也可以直接移除了

Host && Environment

原來的 IHostingEnvironment 改為了 IWebHostEnvironment,原來注入 IHostingEnvironment 的地方需要修改為注入 IWebHostEnvironment

原來 Program 裡使用的 WebHostBuilder 改為 HostBuilder 並配置 `ConfigureWebHostDefaults `,變更如下:

MVC

服務註冊

3.0 裡 MVC 對 ControllerRazorPages 以及 RazorViews 整理,注入服務的時候我們可以只注入自己需要的服務,如果是 WebAPI 專案可以只新增 Controller 需要的服務即可,對應的新增方式:

services.AddControllers(); // WebAPI
services.AddControllersWithViews(); // MVC
services.AddRazorPages(); // RazorPage

JSON 配置

asp.net core 3.0 預設使用微軟新的 JSON,但是推薦還是用 Newtonsoft.Json,比較成熟而且對很多比較特殊的情況都有處理,已然成為了.NET 裡 JSON 序列化的事實標準,使用方式如下:

  1. 引用 nuget 包 Microsoft.AspNetCore.Mvc.NewtonsoftJson

  2. 配置使用 Newtonsoft.Json

services.AddControllersWithViews()
    .AddNewtonsoftJson(options =>
    {
        options.SerializerSettings.ContractResolver = new DefaultContractResolver();
        options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc; // 設定時區為 UTC
    });

Rounting

asp.net core 3.0 推薦使用 endpoint rounting

配置方式如下:

           app.UseStaticFiles();

            app.UseSwagger()
                .UseSwaggerUI(c =>
                {
                    // c.RoutePrefix = string.Empty; //
                    c.SwaggerEndpoint($"/swagger/{ApplicationHelper.ApplicationName}/swagger.json", "活動室預約系統 API");
                    c.DocumentTitle = "活動室預約系統 API";
                });
                
            app.UseRouting(); // 放在 UseStaticFiles 之後

            app.UseCors(builder => builder.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin());

            app.UseRequestLog();
            app.UsePerformanceLog();

            app.UseAuthentication();
            app.UseAuthorization(); // 放在 UseAuthentication 之後

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers(); // 屬性路由
                endpoints.MapControllerRoute("Notice", "/Notice/{path}.html", new
                {
                    controller = "Home",
                    action = "NoticeDetails"
                }); // 自定義路由
                endpoints.MapControllerRoute(name: "areaRoute", "{area:exists}/{controller=Home}/{action=Index}"); // 區域路由
                endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}"); // 預設路由
            });

Swagger

更新 swagger 依賴到最新的 5.0.0-rc-x 版本(還沒發穩定版,需要顯示預覽版本才能看到)

services.AddSwaggerGen(options =>
{
    options.SwaggerDoc(ApplicationHelper.ApplicationName, new Microsoft.OpenApi.Models.OpenApiInfo { Title = "活動室預約系統 API", Version = "1.0" });

    options.IncludeXmlComments(System.IO.Path.Combine(AppContext.BaseDirectory, $"{typeof(Models.Notice).Assembly.GetName().Name}.xml"));
    options.IncludeXmlComments(System.IO.Path.Combine(AppContext.BaseDirectory, $"{typeof(API.NoticeController).Assembly.GetName().Name}.xml"), true);
});

這裡沒有用到 OperationFilter,如果用到了 OperationFilter,可能需要引入 Swashbuckle.AspNetCore.Filters 這個包,詳細參考:https://www.cnblogs.com/laozhang-is-phi/p/11520048.html#autoid-6-0-0

Docker

Dockerfile 裡基礎映象需要更新到 3.0

示例 dockerfile:

FROM mcr.microsoft.com/dotnet/core/sdk:3.0-alpine AS build-env
WORKDIR /src

# Copy csproj and restore as distinct layers
COPY ActivityReservation.Common/*.csproj ActivityReservation.Common/
COPY ActivityReservation.Models/*.csproj ActivityReservation.Models/
COPY ActivityReservation.DataAccess/*.csproj ActivityReservation.DataAccess/
COPY ActivityReservation.Business/*.csproj ActivityReservation.Business/
COPY ActivityReservation.Helper/*.csproj ActivityReservation.Helper/
COPY ActivityReservation.WechatAPI/*.csproj ActivityReservation.WechatAPI/
COPY ActivityReservation.AdminLogic/*.csproj ActivityReservation.AdminLogic/
COPY ActivityReservation.API/*.csproj ActivityReservation.API/
COPY ActivityReservation/ActivityReservation.csproj ActivityReservation/

# RUN dotnet restore ActivityReservation/ActivityReservation.csproj
## diff between netcore2.2 and netcore3.0
WORKDIR /src/ActivityReservation
RUN dotnet restore

# copy everything and build
COPY . .
RUN dotnet publish -c Release -o out ActivityReservation/ActivityReservation.csproj

# build runtime image
FROM mcr.microsoft.com/dotnet/core/aspnet:3.0-alpine

LABEL Maintainer="WeihanLi"
WORKDIR /app
COPY --from=build-env /src/ActivityReservation/out .
EXPOSE 80
ENTRYPOINT ["dotnet", "ActivityReservation.dll"]

修改基礎映象一般不會有什麼問題,需要注意的是如果 dockerfile 裡有用到 dotnet publish 且publish 的專案不在當前目錄下,可能會遇到這樣的問題,最後找不到要釋出的檔案。

dotnet core 3.0 cli 有個 breaking change,如果要釋出的專案不在當前目錄下,在 2.x 版本是會發布到專案檔案所在目錄下的,但是 3.0 版本會發布在當前目錄下,比如說執行dotnet publish -c Release ./src/ActivityReservation.csproj -o out命令:

2.x版本會在 src目錄下生成一個 out 資料夾

3.0 版本會在當前目錄下生成一個 out 資料夾,out資料夾和 src 同級

詳細問題可以參考 https://github.com/dotnet/cli/issues/12696

EF

EF Core 3.0 和 asp.net core 3.0 完全獨立,可以在 asp.net core 3.0 的專案裡使用 2.x 的 EF Core

EF Core 3.0 有個 breaking change,不再隱式支援客戶端渲染資料,這可以讓你更清晰的知道哪些條件和在資料庫執行的哪些條件是在本地執行的,但是實際試用下來,還是有很多問題的,在 EF 的基礎上封裝了一層,試用表示式樹來拼接查詢條件,但是最後執行的時候會有問題,但是簡化後的條件實際上並不會在客戶端執行任何過濾操作,所以暫時不推薦試用 ef core 3.0,而且更新之後可能會遇到其他的問題,詳見issue https://github.com/aspnet/EntityFrameworkCore/issues/18025

現在的專案使用 ef core2.1 + asp.net core3.0 執行

More

其他的地方應該也有需要修改的地方,歡迎補充

Reference

  • https://www.cnblogs.com/stulzq/p/11497624.html
  • https://www.cnblogs.com/laozhang-is-phi/p/11520048.html
  • https://docs.microsoft.com/en-us/aspnet/core/migration/22-to-30?view=aspnetcore-3.0&tabs=visual-studio
  • https://github.com/WeihanLi/ActivityReservation/pull/28/files