行业
技术
组织规模
大型(1,000-9,999 名员工)
国家/地区
美国
技术
公司
Microsoft Teams “MiddleTier” 是支持 Microsoft Teams 中各种方案的内部服务。它由 700 多个 API 组成,是由 Microsoft 的 10 多个团队维护的最大服务之一。在过去两年中,此服务下的 50 多个项目(库、测试、应用程序)已转换到 .NET Standard 2.0 和 .NET Core 3.1,具有等效的功能和性能(或更佳),目前在生产中已几乎完全在 .NET Core 3.1 上运行,并且希望下一步移动到 .NET 6。在此迁移之前,该服务使用 ASP.NET Core 2.2 MVC 管道在 .NET Framework 4.6.2 上运行。它在 Azure Service Fabric上运行,并且部署在 35 个 Azure 数据中心。
此迁移的范围很大,因为就它每天为数百名使用它的开发人员提供的功能而言,MiddleTier 是一项超大型服务。
迁移动机
团队乐于迁移到 .NET Core 3.1 的原因如下:
- 性能和成本效益提升
- .NET Framework 4.6.2 可能即将过期
- 跨平台支持
- 迁移到新式框架以获得更好的开发人员体验
迁移到 .NET Core 3.1 后的好处
迁移到 .NET Core 3.1 后,团队已注意到以下改进:
- 25% 的 CPU 改进
- 降低了大约 25% 的基础结构成本
- 改进的线程池使用率
- 降低了向年度 .NET 版本迁移的技术债务和工作量
下图显示了 .NET Framework 与 .NET Core 之间的比较。将来在 .NET 6 上,我们应会看到进一步的改进。



方法
整体迁移分为三个阶段进行:
他们还选择将应用程序设置为多目标,即同时面向 .NET Framework 和 .NET Core,以便可以同时拥有两个可用的二进制文件,并且可以继续缓慢推出 .NET Core。
学习
OData 和其他 REST API 无法共享路由前缀
他们的服务包含几个 OData 终结点以及许多 REST 终结点。这两类终结点共享相同的路由前缀。此设置过去在 .NET Framework 中可正常工作,但由于路由更改,已停止在 .NET Core 中正常工作。他们必须将 OData API 移动到其他路由前缀才能解决此问题。
OData 客户端库的性能问题
与 .NET Framework 相比,使用 OData 客户端调用下游 OData API 的 HttpWebRequest 模式会导致更高的延迟。这是由于框架不缓存连接的 .NET Core 中的回归所导致的。此问题已在较新版本的 .NET 中得到解决。
Azure 服务总线 SDK 问题
作为此迁移的一部分,必须升级 Azure 服务总线 SDK,因为旧版本与 .NET Standard 不兼容。最新版本的 Azure 服务总线 SDK 以 JSON 格式发送请求有效负载,而旧版 SDK 则以 XML 格式发送有效负载。要继续使用 XML 有效负载,必须使用 DataContractSerializer。
适用于多目标的 Service Fabric 项目中的问题
Service Fabric 项目(sfproj)本身不支持多目标。他们必须在生成管道中执行解决方法,以便为两个目标框架生成 Service Fabric 包。
关于较旧版本的 MimeKit NuGet 的问题
较旧版本的 MimeKit 可能遇到与双字节字符有关的问题,因此在此方案中建议进行特定于语言的验证。他们在向位于亚洲地区的部署推出时发现了类似的问题。
经典 ASP.NET 奇妙之处
- 必须移除在 .NET Core 中标记为内部的某些 .NET Framework 类的用法。
- 如面向版本 3.0 和 3.1 的 ASP.NET Core 重大更改一文所述,已从操作名称中删除 MVC 异步后缀。如果任何代码路径依赖于操作名称,则可能导致行为发生更改。
- 默认情况下,从 .NET Core 3.0 开始,已在所有服务器上禁用同步 IO 操作,如 dotnet/aspnetcore#7644 GitHub 问题中所述。
- 将 StreamContent 作为 HTTP 请求内容发送时,Content.Headers 中未设置 Content-Length 标头。这可能会导致下游调用出错。
- .NET framework 为字符串生成稳定的哈希代码,但 .NET Core 则不会生成。
- System.ComponentModel.DataAnnotations 命名空间中的必需属性在 .NET Core 中的行为会有所不同。在 .NET Framework 上,此属性不会对非 null 字段执行任何模型验证,但在 .NET Core 上则会执行此操作。
未来
每个新版本的 .NET 都附带了重大的生产力和性能改进,可继续帮助实现我们构建可复原、可缩放、高性能和安全服务的目标。团队下一步将通过升级到 .NET 6 来继续利用 .NET 中所做的改进。