.Net Core 2.2 升級到 .Net Core 3.1 填坑


今天嘗試將自己的小項目從.net core 2.2 升級到 3.1,發現並不是簡單的 一鍵升級 這么簡單(慚愧)!!記錄下升級的步驟以及過程中遇到的問題。

 

所有項目目標框架選擇為.net core 3.1

發現項目依賴項的包中出現黃色感嘆號,編譯成功,但是項目啟動后顯示警告。

 

原因警告已經說的很清楚了,移除Microsoft.AspNetCore.App和Razor.Design引用。

項目啟動更改

原啟動方式

        public static void Main(string[] args)
        {
            CreateWebHostBuilder(args).Build().Run();
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .ConfigureLogging((hostingContext,logging)=> {
                    logging.ClearProviders();
                    logging.AddConsole();
                    logging.AddNLog();
                })
                .UseStartup<Startup>();

現啟動方式,注意,采用了更通用的Host替代了原來的WebHost

        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .UseServiceProviderFactory(new AutofacServiceProviderFactory())
                .ConfigureWebHostDefaults(webBuilder =>
                    {
                        webBuilder.UseStartup<Startup>()
                                .ConfigureLogging((hostingContext, logging) =>
                                {
                                    logging.ClearProviders();
                                    logging.AddConsole();
                                    logging.AddNLog();
                                });
                    });

 

更新所有Nuget包至最新

mvc項目異常來了!

Application startup exception: System.InvalidOperationException: Endpoint Routing does not support 'IApplicationBuilder.UseMvc(...)'. To use 'IApplicationBuilder.UseMvc' set 'MvcOptions.EnableEndpointRouting = false' inside 'ConfigureServices(...).

原本MVC注冊方式發生變化,不再支持 app.UserMcv();

修改成以下方式

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

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

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

當然網上也提供了支持原類似的注冊方式,可參考 https://www.cnblogs.com/tianma3798/p/11909293.html

部分依賴組件注冊方式也發生了變化。例如Autofac,原因是ConfigureServices不再支持返回System.IServiceProvider。

原本的注冊方式

        public IContainer ApplicationContainer { get; private set; }
        private IServiceProvider ConfigureInjectionsWithAutofac(IServiceCollection services)
        {
            var builder = new ContainerBuilder();
            //very import
            //正常返回IServiceProvider 並不能替代原IServicePrivder。還需要自定義ServiceScopeFactory保證RequestServices返回的也是你自定義的ServiceProvider。
            //詳細見https://www.cnblogs.com/artech/p/3rd-party-di-integration.html
            //此處autofac做了特殊處理
            builder.Populate(services);

            //TODO 如何支持多個數據庫鏈接DbContext?
            //具體的 Repository,可以依賴具體的 DbContext
            builder.RegisterType<MyDataContext>().As<DbContext>().InstancePerLifetimeScope();

            #region repository

            builder.RegisterType<UserRepository>().As<IUserRepository>().InstancePerLifetimeScope();

            #endregion

            #region domainService

            builder.RegisterType<UserDomainService>().As<IUserDomainService>().InstancePerLifetimeScope();

            #endregion

            #region appService

            builder.RegisterType<UserAppService>().As<IUserAppService>().InstancePerLifetimeScope();

            #endregion

            #region middlerware

            builder.RegisterType<GlobalExceptionMiddleware>().AsSelf().InstancePerLifetimeScope();
            builder.RegisterType<GlobalApiLoggingMiddleware>().AsSelf().InstancePerLifetimeScope();

            #endregion

            ApplicationContainer = builder.Build();

            return new AutofacServiceProvider(ApplicationContainer);
        }

現在的注冊方式,在program.cs類中 UseServiceProviderFactory

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .UseServiceProviderFactory(new AutofacServiceProviderFactory())
                .ConfigureWebHostDefaults(webBuilder =>
                    {
                        webBuilder.UseStartup<Startup>()
                                .ConfigureLogging((hostingContext, logging) =>
                                {
                                    logging.ClearProviders();
                                    logging.AddConsole();
                                    logging.AddNLog();
                                });
                    });

在Startup.cs類中新增 ConfigureContainer

        public void ConfigureContainer(ContainerBuilder builder)
        {
            #region repository

            builder.RegisterType<UserRepository>().As<IUserRepository>().InstancePerLifetimeScope();

            #endregion

            #region domainService

            builder.RegisterType<UserDomainService>().As<IUserDomainService>().InstancePerLifetimeScope();

            #endregion

            #region appService

            builder.RegisterType<UserAppService>().As<IUserAppService>().InstancePerLifetimeScope();

            #endregion

            #region middlerware

            builder.RegisterType<GlobalExceptionMiddleware>().AsSelf().InstancePerLifetimeScope();
            builder.RegisterType<GlobalApiLoggingMiddleware>().AsSelf().InstancePerLifetimeScope();

            #endregion
        }

webapi返回值問題。我正好有個接口返回的是JObject。升級到3.1后報 System.NotSupportedException: The collection type 'Newtonsoft.Json.Linq.JObject' is not supported。原代碼如下

        [Route("headclaims")]
        [HttpGet]
        public IActionResult HeadClaims()
        {
            var claimTypes = new List<string> { "name", "phone", "userId", "introduce","client_id" };
            var claimHeads = Request.Headers.Where(x => claimTypes.Contains(x.Key));
            var user = Request.HttpContext.User;
            if (claimHeads == null) return Ok();
            var returnObj = new JObject();
            foreach (var ch in claimHeads)
            {
                returnObj.Add(ch.Key, ch.Value.ToString());
            }
            return Ok(returnObj);
        }

最后返回要修改成這樣,才能正確返回。

            return Ok(returnObj.ToString());

Entityframework 問題。下面代碼在2.2是可以運行的,但是3.0會報linq錯誤。

        public async Task<UserEntity> GetUserAsync(string name, string password)
        {
            return await _dbSet.FirstOrDefaultAsync(x => string.Equals(x.Name, name, StringComparison.CurrentCultureIgnoreCase)
                   && string.Equals(x.Password, password, StringComparison.CurrentCultureIgnoreCase));
        }

修正為

        public async Task<UserEntity> GetUserAsync(string name, string password)
        {
            return await _dbSet.FirstOrDefaultAsync(x => x.Name == name
                   && x.Password == password);
        }

原因應該在這里能解釋:https://docs.microsoft.com/zh-cn/ef/core/querying/client-eval。

 

至此,我的小項目正確運行起來!!

最后貼下官方的遷移指引,我承認之前沒看~~~。一定要看一下!!!

https://docs.microsoft.com/zh-cn/aspnet/core/migration/22-to-30?view=aspnetcore-3.1&tabs=visual-studio

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM