记将一个大型客户端应用项目迁移到 dotnet 6 的经验和决策

在经过了两年的准备,以及迁移了几个应用项目积累了让我有信心的经验之后,我最近在开始将团队里面最大的一个项目,从 .NET Framework 4.5 迁移到 .NET 6 上。这是一个从 2016 时开始开发,最多有 50 多位开发者参与,代码的 MR 数量过万,而且整个团队没有一个人能说清楚项目里面的所有功能。此项目引用了团队内部的大量的基础库,有很多基础库长年不活跃。此应用项目当前也有近千万的用户量,迁移的过程也需要准备很多补救方法。如此复杂的一个项目,自然需要用到很多黑科技才能完成到 .NET 6 的落地。本文将告诉大家这个过程里,我踩到的坑,以及学到的知识,和为什么会如此做

前文

准确来说,我在这个过程其实算是最后一公里,我估算了工作量,大概将这个项目从 .NET Framework 4.5 迁移到 .NET 6 上的工时约 1.5 年人。虽然我现在说的是我用了五周的时间就完成了,但实际上在此前的准备工作是没有被我算上的。此前的工作包括什么?还包括将各大基础库更改为支持 dotnet core 的版本,填补 dotnet core 和 dotnet framework 的差异,例如 .NET Remoting 和 WCF 等 IPC 的缺失。更新打包平台和构建平台,使支持 dotnet core 的构建和打包。更新软件的 OTA 也就是软件自动更新功能,用于支持复杂的灰度发布功能和测试 .NET 6 环境支持。逐步从边缘到核心,逐个应用项目迁移,进行踩坑和积累经验

在做足了准备之后,再加上足量的勇气,以及一个好的时机,在整个团队的支持下,我就开始进行最后一公里的迁移

其实在进行最后的从 .NET Framework 4.5 换到 .NET 6 之前,整个团队包括我都是完全没有想到还有如此多的坑需要填的。这个庞大的项目用了多少奇奇怪怪的黑科技还是没有人知道的。在记录本文时,我和伙伴们说,也许世界上没有其他的团队也会遇到咱的问题了

背景

一个从 2016 时开始开发,最多有 50 多位开发者参与,而且这些开发者们没几位是省油的,有任何东西都需要自己造的开发者,有任何东西只要能用别人做好的绝不自己造的开发者,有写代码上过央视的开发者,有参与制定国家标准的开发者,有一个类里面一定要用满奇特的设计模式的开发者,有在代码注释里面一定要放大佛的开发者,有学到啥黑科技就一定要用上的开发者,有只要代码和人一个能跑就好的开发者,有睁着眼睛说瞎话代码和注释完全是两回事的开发者,有代码注释是文言文的开发者,有代码注释是全英文的开发者,有注释和文档远超过代码量的开发者,有中文还没学好的开发者,有喜欢挖坑而且必须自己踩的开发者,有啥东西都需要加日志的开发者,有十分帅穿着西装写代码的开发者,有穿着女装写代码的开发者,有在代码里面卖萌的开发者,有 这个函数只有我才能调用 的开发者,有相同的逻辑一定要用不同的方式实现的开发者,有在奔跑的坦克上换引擎的开发者

在本次迁移的过程,还有一些坑需要填。其中一个就是 dotnet core 里面,没有一个多 Exe 入口的客户端应用的最佳实践。这里面涉及到客户端应用独立管理运行时环境时,多个 Exe 的冲突处理和安装完成之后的文件夹体积的矛盾。这个也是本文分享的重点

本次还带了一些需求,包括: 在确定系统环境满足的情况下,低限度依赖系统,且需要做到不会被用户系统上所安装的 dotnet 运行时所影响。另外,考虑到后续要支持产品线内多个应用都共用运行时,但此运行时不能和其他团队,其他公司所共有避免被魔改,还需要进行一些尝试逻辑。最后,对使用的 WPF 版本是要求定制的,也就是说需要在官方发布版本的基础上,更改部分逻辑,满足特殊的产品需求

这就意味着将 dotnet 重新分发,设置为团队完全控制的库。这个变更之后,在更新到 .NET 6 之后,可以执行完全的自主控制 dotnet 框架,包括 WPF 框架。于是可以做的事情就更加多了,无法实现的东西就更少了

为了做到对 WPF 更多的定制化,我将 WPF 框架的地位从原先的应用运行时层,更改为基础库层,地位和 团队里面的基础组件 等 CBB 相同,只是作为底层库而存在,架构上和 最底层的基础库 平级

本次遇到的问题分为两个大类,一个是此项目本身的复杂度带来的问题,另一个是 dotnet 带来的问题。本文只记录 dotnet 所带来的问题,其中更多部分是因为特殊需求定制而导致问题

开发架构

原本的应用开发架构上,所依赖的 .NET Framework 是作为系统组件的存在。系统组件受到系统环境的影响,在国内妖魔鬼怪的环境下,系统组件被魔改被损坏是常态。采用 .NET Framework 的应用有着很大的客服成本,需要帮助用户解决环境问题。随着用户量越来越大,这部分的客服成本也越来越大。这也就是为什么有能投入到如此多资源来更新项目的原因之一

原本的应用开发架构分层如下图

015dfbe7181f126c16869e9375f05507.png

在更新到 dotnet 之后,运行时是在系统层的上方。如此的设计即可减少系统环境的影响,解决大量的应用环境问题

188ace9a8d9428e20e4643ae2f524859.png

从上图可以看到 WPF 是作为运行时的部分存在,但这不利于后续对 WPF 的定制化。我所在的团队期望能完全将 WPF 进行控制,对 WPF 框架做深度定制。当然,本身团队也有此能力,因为我也算是 WPF 框架的官方开发者。这部分深度的定制将会根据定制的不同,部分进行开源

变更后当前的开发架构分层如下图

c0b970be047e767d322a9f76263aba2c.png

让 WPF 作为基础库的一部分而存在,而不再放入运行时里面。计划是产品项里面的多个产品项目是共用 .NET 运行时,单个各个产品之间自己带 WPF 的负载,作为基础库

所遇到的问题

在进行最后一公里的更新就遇到了一些 dotnet core 机制上没有最佳实践的问题

多 AppHost 入口应用的依赖问题

多 Exe 应用的客户端依赖问题是其中的一个机制性问题。当前正在迁移的项目是一个多进程模型的应用,有很多 Exe 的存在。然而 dotnet core 当前没有一个最佳实践可以让多个 Exe 之间完美共享运行时且不受系统所安装的全局 dotnet 运行时影响,同时照顾到安装完成之后的文件夹体积

我列出的问题点如下

  • 多个 Exe 文件之间,如何共享运行时,如果不共享文件夹,各自独立发布,那将让输出文件夹体积非常大

  • 多个 Exe 文件,如果在相同的文件夹进行发布,将会相互覆盖相同的名字的程序集。根据 dotnet 的引用依赖策略,如果有版本不兼容情况,将出现 FileLoadException 错误

  • 不能使用 Program File 共享的全局程序集,因为这个文件夹里面的内容可能被其他公司的应用更改从而损坏,无法使用 dotnet core 环境独立的能力

  • 不能使用 Program File 共享的全局程序集,因为团队内将会对 dotnet 运行时进行定制,例如定制 WPF 程序集,将 WPF 的地位从运行时更改为基础库。这部分定制不能污染其他应用

  • 发布到用户端的运行时版本只能选用稳定的版本,而开发者会使用较新的 SDK 版本,开发构建输出的程序集将引用较新 SDK 版本,如应用运行加载的只是发布到用户端的运行时版本,将会因为版本低于构建版本而出错

  • 发布到用户端的运行时版本,是包含了定制版本的运行时,例如定制的 WPF 程序集。开发时应该引用定制的 WPF 程序集,但是不能引用低于构建版本的用户端的运行时版本

另外由于 dotnet core 和 dotnet framework 对 exe 有机制性的变更,如 dotnet core 的 exe 只是一个 apphost 而已,默认不包含 IL 数据。而 dotnet framework 下默认 exe 里面是包含应用入口以及 IL 数据程序集的。这就导致了原本的 NuGet 分发里面有很多不支持的部分,好在这部分的坑踩平了

然而在进行 AppHost 的定制的时候,却一定和 NuGe

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值