今天尝试将自己的小项目从.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

 

posted on 2020-03-23 16:21  gt1987  阅读(1475)  评论(0编辑  收藏  举报