源宝导读:微软跨平台技术框架—.NET Core已经日趋成熟,已经具备了支撑大型系统稳定运行的条件。本文将介绍明源云ERP平台从.NET Framework向.NET Core迁移过程中的实践经验。

一、背景

随着ERP的产品线越来越多,业务关联也日益复杂,应用间依赖关系也变得错综复杂,单体架构的弱点日趋明显。19年初,平台底层支持了分应用部署模式,将ERP从应用子系统层面进行了切割分离,迈出了从单体架构向微服务架构转型的坚实一步。不久的将来,ERP会进一步将各业务拆分成众多的微服务,而微服务势必需要进行容器化部署和运行管理,这就要求ERP技术底层必须支持跨平台,所以将现有ERP系统从.NET Framework迁移到 .NET Core平台势在必行。

二、遇到的问题和应对策略

ERP在从Framework迁移到Core的时候主要要解决以下问题:

  1. 代码文件和工程迁移。

  2. Aspx文件迁移到Razor。

  3. HttpModule和HttpHandler迁移。

  4. ClownFish的Mvc机制迁移到Asp.Net Core MVC。

  5. 其他一些Windows平台Api迁移到跨平台。

  6. 发布和Docker部署。

以上每个主题中都包含了大量的技术细节,我们后面将陆续发文章分享经验。本文先介绍关于项目工程迁移方面的内容,具体的迁移步骤如下:

  1. dll引用实际是一个层级关系,从启动项目往下找是可以找到一个最底层的依赖的,然后会存在一个依赖顺序(拓扑排序),我们改造的时候也是从最底层开始改造起,逐个工程这样迁移,迁移过程保证编译通过。

  2. 在类库迁移的时候核心有三个点,cs文件迁移,新的工程(.csproj)文件组织,dll引用组织。

  3. 在站点项目迁移的时候需要考虑静态资源(js,css等)的组织。

  4. 在做完这些之后要考虑dll版本和最终打包发布。

三、迁移代码文件

.NET Framework 的 .csproj 文件极其庞大且难以理解,在新的.Net Core中推出了全新的的.csproj组织方式。新的工程文件主要有如下优势:

  • 在版本管理中更容易解决冲突:新方式包含了目录下所有文件,老方式是需要显示的引用(有点像黑名单和白名单的意思),这样声明的文件变得更少,从而减少了多人协作时XML合并冲突的风险。

  • 可以指定多个开发框架,提供更好的兼容性:以往如果要同时兼容.Net3.5和.Net 4.5的话需要建两个工程,通过文件链接来处理多个框架兼容的问题,新的组织方式一个工程文件即可处理。

  • 引用更加简洁:没有对其他项目的基于GUID的引用,这可以提高文件的可读性。同时基于NuGet的引用和路径无关,意味着可以指定任意的NuGet包的位置。

  • 嵌套的引用不需要重复指定(如果 A 引用了 B,B 引用了 C;那么 A 不需要显式引用 C 也能调用到 C)。

项目迁移就是要实现对原来.cs代码进行迁移,实现逻辑的复用,这里有三种迁移代码文件的方式:

1、Copy文件: 将原有的文件复制复制到新文件夹重新组织(基本相当于重新写一套就不赘述了)。

2、文件链接: 使用文件链接只需新建一个工程使用来组织代码,基于Framework和Core可以分别再额外添加文件,下面是示例:

3、多框架:一个工程文件中有多个框架,下面是示例:

我们的策略是,根据不同的情况使用不同的迁移方式:

  1. 对于基础平台,由于是ERP的基础底座,必须保证其迁移后的稳定和兼容,但基础平台的代码量大,功能多,如果仅靠大量测试很难保证整体迁移的质量。由于Core和Framework的Api的一些差异,并不是完全兼容,但微软还是提供了最大限度地功能兼容。为了以最低成本保障迁移质量,最终我们采用的是文件链接的迁移方式

  2. 对于平台的文档服务和配置中心,功能较简单,全面进行回归测试的成本不大,所以我们采用了多框架的迁移方式。虽然.NET Core在HTTP框架方面并不兼容,我们需要重写个别项目,这些项目的代码量不大,所以对迁移质量的影响不大。

  3. 对于平台的调度服务,我们采用重写加上多框架的迁移方式。只是因为调度服务的核心引擎比较简单,我们直接采用重写的迁移方式,这部分后面将会有单独的文章来介绍。

四、处理代码文件兼容

当我们解决了工程层面的兼容之后,引入的文件编译肯定会报错,解决这个问题这个最核心的其实就是条件编译了,示例如下:

虽然可以使用上述手段适配不兼容的API调用,但如果某个API被用到的地方特别多,就会出现大量重复的条件编译,面对这个问题,我们可以将调用API这部分代码抽离成单独的Helper类。举个例子:在Framework和Core中,从Http上下文中取参数的方法存在很大差异,而之前代码中大量调用了这个API方法,我们可以将调用此API的代码封装到一个单独的Helper类,如下代码所示:

上述示例中有如下几点比较重要:

  • 命名空间中使用重命名的方式提供了参数的兼容使调用方代码统一。

  • AsBase这类空方法提供了调用代码的统一。

  • 在方法级别使用了条件编译,结合后续的处理逻辑兼容提供了调用方代码统一。

  • 在方法内部使用了条件编译,直接提供了方法调用的兼容。

在命名空间重命名的技巧中还有另外一个用法也特别有用,还是举例说明:

对比上述代码可以发现,使用占位Attribute的方式代码会简洁很多,还有类似很多技巧这里就不一一说明。

改造过程中总结出以下实践:

  1. 先用最简单的条件编译。

  2. 一个类里面方法和参数的特性导致重复的条件编译比较多,考虑在命名空间部分使用重命名。

  3. 一个类里面方法内部重复的条件编译比较多,考虑用类中私有方法来封装这部分重复逻辑。

  4. 多个类里面方法内部重复的条件编译比较多,考虑用用Helper类来封装。

  5. 如果是方案级别的不一样,考虑用一个接口在Framework和Core中不同的实现来处理。

五、处理包引用

在处理完代码层面兼容之后,还要处理第三方类库的引用的问题。我们先通过下面两张图看看Framework和Core中引用的不同。

Framework引用关系:

Core引用关系:

在Framework中都是平铺的,而在Core中引用是树形结构;比如在Framework中A引用了B,B引用C,A如果要用到C的功能就必须要显式的引用C,但是在CoreA是不需要引用C的。所以我们改造的时候遵循从底层网上改,如果底层引用的包上层就不再引用,这样大大减少了项目中包引用的数量。新的引用机制也带来了一些问题:

  1. 平台周边的类库文件,如果按照原来方式是需要打包两个dll,然后手动添加dll引用,这样使仓库体积变大,同时也不容易维护版本。

  2. 由于.Net Core的模块化更细,一个包可能依赖于很多的其他包,这样就导致了拉取nuget包很慢。

基于上述问题我们引入了Nexus作为我们的包管理工具。通过这个工具可以将自己的类库推送到自己的NuGet仓库管理,它同时还提供了代理的功能可以将远程的包存储到局域网,大大提高了拉包的速度。可能有些同学没有使用过Nexus,这里做一个简单的介绍:

  • 功能: 提供的包类型非常丰富,支持nuget,maven,docker,npm,pypl,yum等,几乎覆盖市面所有流行的语言和工具。

  • Host仓库: 支持自建仓库可以上传自己制作的包并共享出来。

  • Proxy仓库: 支持为其他远程仓库地址代理,通过代理可以将其他网站的软件包缓存到本地,大大提高拉包的效率。

  • Group仓库: 支持分组将多个代理和私服打包成一个组,这样远程包的地址集中管理。

  • 权限管理:在任意一个仓库都可以控制增删改查等权限。

  • 总之:还有更多功能大家可以去试试(强烈推荐)。

六、处理静态文件复用

我们解决了类库的迁移之后,由于在.NetCore改造过程中完全不涉及到前端js,css等文件的改造,所以要保证的js和css可以复用。在Framework中所有的资源文件都是相对于站点根目录的路径,而在Core中所有的资源文件都是在根目录的wwwroot中,而在Core中提供了WebRootPath可以指定资源文件的路径,我们在启动过程中做了如下配置:

.Net Core中可以根据环境变量来加载不同的配置文件,首先会默认加载appsettings.json,在开发环境中会额外的加载 appsettings.Development.json文件,后添加文件的配置项会覆盖先添加文件的相同配置项,这样在生产环境中使用默认的WebRootPath配置,而在开发环境中把WebRootPath指向原来Framework站点路径,即可实现开发环境和生产环境的资源文件复用。

七、处理dll版本迭代

在ERP发布过程中是需要管理版本的,每个dll的版本都应该保持一致,那么就会涉及到如何通过修改一个地方让所有dll版本都升级。

  • 在Framework中我们用到了两种方法:

  1. Assembly文件链接,在周边服务中Assembly中不需要有太多信息,这个时候通过一个只有版本信息的Assembly文件然后通过文件链接方式加入到各个工程中,发布时候只需修改一个Assembly的版本号即可。

  2. 老版本target文件引用,在每个工程中引入如下target文件,然后发布时候修改VersionAssembly中版本号即可。

  • 在Core中我们采用引入props文件(和target文件类似) ,使用方式如下所示:

  • 在Core中通过引入props文件这种方式可以将所有工程的通用描述包含进来,我们还用来在此文件中描述了dll文件签名等其他内容。

    八、程序打包发布

    最后一步就是打包发布了, Framework中发布将编译后的站点目录进行打包,但是在Core中需要调用dotnet命令发布,发布之后还要考虑资源文件,dll版本,使用 dotnet publish {启动项目相对路径} 命令发布即可,在平台服务中我们还使用了将独立发布的模式。

    因为ERP是前后端在一个仓库,而且有众多的资源文件,这里给出发布的脚本仅供大家参考:

    九、总结

    在改造过程中由于要兼容老的Framework的功能,给整个过程带来了很多需要兼容的问题。初看之下可能会很乱,但是在一步步分析之后还是有思路可以做,并且在改造过程中大量采用了条件编译延伸出来的技巧,使改造过程的思路和方法越来越清晰,最终完成了整个改造专项。

    在整个过程中也遇到代码不兼容的场景,这个时候就考虑从功能层面来兼容,比如:授权和权限,页面路由,资源文件合并和替换等等,这些具体到功能细节改造的部分,将会在后面文章中陆续进行介绍,敬请期待。

    ------ END ------

    作者简介

    熊同学: 研发工程师,目前负责ERP平台相关的设计与开发工作。

    也许您还想看

    .NET Core MVC扩展实践

    研发协同平台架构演进

    明源云助手产品日志服务的演化历程

    ERP缓存实践经验分享

【复杂系统迁移 .NET Core平台系列】之迁移项目工程相关推荐

  1. 【复杂系统迁移 .NET Core平台系列】之调度服务改造

    源宝导读:微软跨平台技术框架-.NET Core已经日趋成熟,已经具备了支撑大型系统稳定运行的条件.本文将介绍明源云ERP平台从.NET Framework向.NET Core迁移过程中的实践经验. ...

  2. 【复杂系统迁移 .NET Core平台系列】之认证和授权

    源宝导读:微软跨平台技术框架-.NET Core已经日趋成熟,已经具备了支撑大型系统稳定运行的条件.本文将介绍明源云ERP平台从.NET Framework向.NET Core迁移过程中的实践经验. ...

  3. 【复杂系统迁移 .NET Core平台系列】之静态文件

    源宝导读:微软跨平台技术框架-.NET Core已经日趋成熟,已经具备了支撑大型系统稳定运行的条件.本文将介绍明源云ERP平台从.NET Framework向.NET Core迁移过程中的实践经验. ...

  4. 【复杂系统迁移 .NET Core平台系列】之界面层

    源宝导读:微软跨平台技术框架-.NET Core已经日趋成熟,已经具备了支撑大型系统稳定运行的条件.本文将介绍明源云ERP平台从.NET Framework向.NET Core迁移过程中的实践经验. ...

  5. 【复杂系统迁移 .NET Core平台系列】之应用发布与部署

    源宝导读:微软跨平台技术框架-.NET Core已经日趋成熟,已经具备了支撑大型系统稳定运行的条件.本文将介绍明源云ERP平台从.NET Framework向.NET Core迁移过程中的实践经验. ...

  6. rsviwe32 7.6 授权_「复杂系统迁移 .NET Core平台系列」之认证和授权

    源宝导读:微软跨平台技术框架-.NET Core已经日趋成熟,已经具备了支撑大型系统稳定运行的条件.本文将介绍明源云ERP平台从.NET Framework向.NET Core迁移过程中的实践经验. ...

  7. 抖音 -抖店开放平台 SDK 实现及项目工程

    抖音 - 抖店开放平台 SDK 抖音 - 抖店开放平台:https://op.jinritemai.com/ 该 SDK 已实现 API 接口调用和消息推送验证解析 项目地址 github: gite ...

  8. 查缺补漏系统学习 EF Core 6 - 原始 SQL 查询

    推荐关注「码侠江湖」加星标,时刻不忘江湖事 这是 EF Core 系列的第五篇文章,上一篇文章盘点了 EF Core 中的几种数据查询方式. 但是有有时候,我们可能无法用标准的 LINQ 方法完成查询 ...

  9. 查缺补漏系统学习 EF Core 6 - 数据查询

    这是 EF Core 系列的第四篇文章,上一篇文章讲述了 EF Core 中的实体迁移与数据播种. 这篇文章盘点一下 EF Core 的几种数据查询方式,内容较多分上下两篇. 点击上方或后方蓝字,阅读 ...

最新文章

  1. 中关村开源创新大赛-达闼赛道如火如荼进行中
  2. cxf 整合 spring 时 java.lang.VerifyError异常
  3. ImportError: No module named setuptools
  4. 【机器学习基础】在机器学习项目中该如何选择优化器
  5. Codeforces 刷题记录(已停更)
  6. JAVA语法——自动类型转换和强制类型转换
  7. CTS(22)---GMS认证-Android8.x新增cts测试(VTS下测试GSI版本)
  8. android 判断listview是否为空,ListView为空时显示空视图
  9. 1041. 考试座位号(15)-PAT乙级真题
  10. Gitlab管理Create Merge Request,new Merge Request创建合并请求
  11. PB 程序发布相关
  12. Atitit 网盘使用法 艾提拉著 目录 1. 需要解决几个问题 2 1.1. 多关键词搜索的问题 使用every索引解决 2 1.2. 重要文具类索引使用分类索引 日志 crm类增加000前缀
  13. GO语言+区块链视频教程,GO语言+区块链学习线路图(含大纲+视频+资料)
  14. 星空特效HTML代码,HTML5特效库 HTML5+JS全屏星空特效源码
  15. AI如何修改画布尺寸? ai怎么设置画布大小_AI教程自学网
  16. Linux安装后的配置操作
  17. office2013来了
  18. 玩客云设置linux权限,玩客云退出链克怎么禁止硬盘缓存?.onething_data文件禁止缓存玩客云关闭上传退出链克...
  19. 智能语音计算器(二)
  20. P1425 小鱼的游泳时间 题解

热门文章

  1. thinkphp3.2 jquery ajax巧妙使用
  2. Microsoft AJAX Client Library规范的实例
  3. 如何从Internet Explorer或Edge迁移到Chrome(以及为什么要迁移)
  4. 对01背包的分析与理解(图文)
  5. Mybatis中jdbcType和javaType的对应关系
  6. 将VNC 安装在Centos 7步骤
  7. 能上架App的GooglePlay开发者账号获取流程
  8. 微软 改变 开源【几个站点】
  9. 切图崽的自我修养-规范CSS元素命名
  10. FZU Problem 2030 括号问题