vc 将已有项目打包成dll 并应用于其他项目_【复杂系统迁移 .NET Core平台系列】之迁移项目工程...

4fbdc981bd218e26336746b439fdc1bc.png

4fed8999d967c66b3ab3008e7689f839.png

源宝导读:微软跨平台技术框架—.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可以分别再额外添加文件,下面是示例:

d86ff12d796c8fd2310ef20afed43ac8.png

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

2e4968f21453c5851f55df4fe496d2a4.png

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

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

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

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

四、 处理代码文件兼容

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

b0f23a2efb472fb56aa2ce9c5bc27e8e.png

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

4a4137b799cddf1b5ab5ed0969bbb33c.png

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

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

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

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

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

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

63681a45090bcf36d0924e45a5e7e197.png

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

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

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

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

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

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

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

五、处理包引用

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

Framework引用关系:

3a1060b21b142b7ff2c3fdc8b981e523.png

Core引用关系:

6b1f31ff1a6dc6a9bf319767dbe63a39.png

    在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可以指定资源文件的路径,我们在启动过程中做了如下配置:

35a68a3356da4fbad92d50395949cc97.png

    .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文件类似) ,使用方式如下所示:

01e05f673093b06b52d6d60dd654803a.png

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

八、程序打包发布

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

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

f2caefaae0a157c3713369184ff9f528.png

九、总结

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

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

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

作者简介

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

也许您还想看

.NET Core MVC扩展实践

研发协同平台架构演进

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

ERP缓存实践经验分享

216423899d2727e1a97014ffb76cedfa.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值