0
点赞
收藏
分享

微信扫一扫

翻译:使用 CoreWCF 升级 WCF 服务到 .NET 6

静守幸福 2022-05-14 阅读 97

翻译:使用 CoreWCF 升级 WCF 服务到 .NET 6

原文地址:​​https://devblogs.microsoft.com/dotnet/upgrading-a-wcf-service-to-dotnet-6/​​

大约在 3 年之前,我发布过一篇​​将一个 WPF 应用迁移到 .NET Core 3 演练过程的博客​​。这是一个被称为 Bean Trader 的简单商用交易示例程序。当时,我只能迁移示例解决方案的一部分。这个 Bean Trader 解决方案包括一个 WPF 客户端应用和一个客户端用来发布和接受交易的服务器端应用。客户端与服务器端的通讯使用 WCF。因为 .NET Core 3 ( 以及后继版本如 .NET 5 和 .NET 6 ) 支持客户端的 WCF API,但是不支持服务器端,我只能迁移 Bear Trader 的客户端部分,而遗留下服务器端继续运行在 .NET Framework 上。

由于近期 CoreWCF 1.0 发布了,我期待完成将 Bean Trader 升级到 .NET 6 上!

1. 关于 CoreWCF

CoreWCF 是一个社区驱动的项目,使得 WCF 可以运行在现代的 .NET 版本上。尽管 CoreWCF 不是微软拥有的项目,微软已经宣布它将提供对 CoreWCF 的产品支持。对于新的开发工作推荐采用最新的技术,像 gRPC 和 ASP.NET WebAPI,但是对于需要迁移到 .NET 6 的现存的重度依赖于 WCF 技术的项目来说, CoreWCF 对于提供了巨大的帮助。

尽管 CoreWCF 支持众多的 WCF 常见使用场景,它并不支持全部的 WCF 功能。你的迁移过程体验非常依赖于你对 WCF 的使用与包含在 CoreWCF 中的功能的交集。如果你使用的功能还没有包含在 CoreWCF 中,请在 ​​Feature Roadmap​​ 中提供反馈,以便 CoreWCF 项目的维护者可以基于社区的需求优先安排工作。

2. 关于示例项目

示例项目 Bean Trader ( ​​GitHub 地址​​ ) 是多年以前,我在演示如何迁移到 .NET Core 的时候创建的示例。因为该示例本来是仅仅用来展示如何迁移客户端,Bean Trader 服务就非常简单。它包含一个含有模型和接口的类库,以及一个用来托管 WCF 服务的控制台应用程序 ( 使用支持证书验证的 Net.Tcp 传输 )。支持客户端发出或者接受交易不同颜色的豆子。尽管该示例应用很小,我想它对于展示迁移到 .NET 6 的过程还是有用的。

翻译:使用 CoreWCF 升级 WCF 服务到 .NET 6_asp.net

3. 迁移

3.1 运行升级助理

为了使得迁移更快捷,我将使用 ​​.NET 升级助理​​。升级助理是用来帮助用户从 .NET Framework 升级到 .NET Standard 和 .NET 6 的命令行程序,使用交互方式。升级助理还不能自动从 WCF 迁移到 CoreWCF ( 尽管以及安排在计划中 ),运行该工具仍然是有帮助的,因为项目文件可以迁移,NuGet 包的引用可以被升级,以及其它处理等等。在该工具执行之后,我将手工完成从 WCF 迁移到 CoreWCF 的需要的变更处理。

为了安装升级助理,我运行如下的 .NET SDK 命令:

dotnet tool install -g upgrade-assistant

升级助理安装之后,我可以在 BeanTrader 解决方案上运行它来开始迁移过程。通过在解决方案 ( 而不是特定项目上 ) 运行,我可以通过执行一次该工具,来升级类库和服务器控制台应用两者。

升级解决方案的命令:

upgrade-assistant upgrade BeanTrader.sln

该工具随即指导我进行一系列的升级步骤 ( 这会通过升级助理自动处理 ),如下所示:

翻译:使用 CoreWCF 升级 WCF 服务到 .NET 6_客户端_02

我通过升级助理的完整步骤如下:

  1. 选择入口点。这支持我选择希望运行在 .NET 6 上的项目。基于该选择,升级助理将决定要升级的项目以及升级的次序。我选择 ​​BeanTraderServer​
  2. 选择一个项目进行升级。这过渡到该工具开始升级指定项目。它建议我先升级 ​​BeanTraderCommon​​ 项目,然后升级 ​​beanTraderServer​​ 项目更加合理,所以我选择该升级顺序。
  3. 备份 ​​BeanTraderCommon​
  4. 将 ​​BeanTraderCommon​​ 项目转换为 SDK 风格的项目
  5. 升级 ​​BeanTraderCommon​​ 的 NuGet 包。该步骤替换对 System.ServiceModel 程序集的引用,使用 NuGet 包,例如 System.ServiceModel.NetTcp 来代替。
  6. 升级 ​​BeanTraderCommon​​ 的目标架构 ( TFM )。该工具建议使用 .NET Standard 2.0,因为该项目是一个纯类库项目,没有任何 .NET 6 特定依赖。
  7. 此时,对辅助项目的升级已经完成,升级助理切换到升级 ​​BeanTraderServer​
  8. 备份 ​​BeanTraderServer​
  9. 转换 ​​BeanTraderServer​​ 项目到 SDK 风格
  10. 将 System.ServiceMoel 引用替换为等价的 NuGet 包,如在 ​​BeanTraderCommon​​ 项目中一样
  11. 升级 ​​BeanTraderServer​​ 项目的目标框架。工具建议为 .NET 6,因为该项目是控制台应用
  12. 禁用不再支持的配置节。升级助理检测到 ​​BeanTraderServer​​ 在它的 app.config 文件中有一个 ​​system.ServiceModel​​ 配置节,它不再被 .NET 6 所支持 ( 会导致运行时错误 ),所以它为我注释掉了。最后,我们将会在其它文件中重用这段注释掉的配置节,来配置我们的 CoreWCF 服务。
  13. 在检查 C# 源是否有任何必要的更改时,升级助手会发出有关 WCF 使用情况的警告。警告消息提醒我,BeanTraderServer 使用服务器端 WCF API,这些 API 在 .NET 6 上不受支持,并且该工具未进行升级。它告诉我,我需要手动进行更改,并建议升级到 CoreWCF、gRPC 或 ASP.NET Core。

    翻译:使用 CoreWCF 升级 WCF 服务到 .NET 6_.net_03

  14. 清理升级。此刻,升级助理完成工作,所以它删除一些临时文件并退出。

3.2 CoreWCF 迁移

现在升级助理已经完成了升级过程,是时候升级 CoreWCF 了。在 Visual Studio 中打开 Bean Trader 解决方案,我发现 BeanTraderCommon 类库可以成功构建。项目升级到 .NET Standard 已经完成了。而 ​​BeanTraderServer​​ 项目有一些错误,可以想到,关联到不能找到某些 WCF 类型。

翻译:使用 CoreWCF 升级 WCF 服务到 .NET 6_客户端_04

为了开始升级到 CoreWCF,我添加 CoreWCF.NetTcp NuGet 包的 1.0 版本引用。我还替换了 ​​using System.ServiceModel;​​​,在 BeanTrader.cs 中导入 ​​using CoreWCF;​​。除了在 program.cs 中我创建 ServiceHost 的错误之后,这解决了其它所有错误。

CoreWCF 构建于 ASP.NET Core 之上,所以我需要升级该项目来启动一个 ASP.NET Core 宿主。BeanTrader 示例是一个自托管的服务项目,所以我只需要做一小点修改来设置一个 ASP.NET Core 宿主来运行我的服务,而不是直接使用 ServiceHost 完成。为了完成这一点,我将项目的 SDK 升级为 ​​Microsoft.NET.Sdk.Web​​ ( 因为项目使用了 ASP.NET Core ),将应用的 Main() 方法改为 async,并使用下面代码替换了对 ServiceHost 的设置。

存在不同类型的 WCF 项目 ( 不都是直接创建并运行 ServiceHost ),但所有的 CoreWCF 应用都是运行在 ASP.NET Core 的端点上。这里展示的代码使用新的 .NET 6 的 ​​minimal API​​​ 语法,来使用最少的代码启动宿主并运行,它也可以微调为使用 ASP.NET Core 语法 ( 例如有独立的 Startup.cs ),如果你愿意的话,​​CoreWCF 示例中​​演示了这两种方式。

注意证书的配置是从原来的示例项目中复制过来的,只用于演示目的。真实的场景下应该使用来自机器的证书存储来使用证书,或者使用安全的位置,比如 Azure 的 Key Vault。另外,这也很好地演示了在使用 CoreWCF 的时候,宿主的属性如何修改,但是设置服务器证书是特别针对 NetTcp 场景的。对于 HTTPS 端点,SSL 通过 ASP.NET Core API 设置,与其它的 ASP.NET Core 应用一样。

var builder = WebApplication.CreateBuilder();

// Add CoreWCF services to the ASP.NET Core app's DI container
builder.Services.AddServiceModelServices();

var app = builder.Build();

// Configure CoreWCF endpoints in the ASP.NET Core host
app.UseServiceModel(serviceBuilder =>
{
serviceBuilder.ConfigureServiceHostBase<BeanTrader>(beanTraderServiceHost =>
{
// This code is copied from the old ServiceHost setup and configures
// the local cert used for authentication.
// For demo purposes, this just loads the certificate from disk
// so that no one needs to install an untrusted self-signed cert
// or load from KeyVault (which would complicate the sample)
var certPath = Path.Combine(Path.GetDirectoryName(typeof(Program).Assembly.Location), "BeanTrader.pfx");
beanTraderServiceHost.Credentials.ServiceCertificate.Certificate = new X509Certificate2(certPath, "password");
beanTraderServiceHost.Credentials.ClientCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
});
});

await app.StartAsync();

我还使用 ​​await app.StopAsync()​​​ 替换了原来应用中的 ​​host.Close()​​ 调用。

3.3 升级配置信息

如前所提及,.NET 6 默认没有包含 ​​system.serviceModel​​ 配置节。但是众多现存的 WCF 应用程序使用 app.config 和 web.config 来设置绑定配置。为了更容易迁移,CoreWCF 包含了可以从 xml 配置文件中显示加载配置信息的 API。

为了使用 Bean Trader 服务器的 WCF 配置,我从添加 ​​CoreWCF.ConfigurationManager​​​ NuGet 包开始。然后,我把原来应用的 app.config 配置文件中的 ​​system.serviceModel​​​ 配置节 ( 它被升级助理注释掉了 ),复制到一个新的配置文件中。该配置文件可以使用任意名称,不过我命名它为 ​​wcf.config​​。

在 WCF 与 CoreWCF 之间支持哪些 WCF 配置存在一些不同,所以我需要对 ​​wcf.config​​ 做一些如下的修改:

  1. ​IMetadataExchange​​ 还不被 CoreWCF 支持,所以删除 mex 端点。我可以仍然使得 WSDL 可以被下载,记住,我随后将展示如何做到这一点。
  2. 在服务模型配置中,元素 ​​\<host>​​ 不被支持。相反,端点的监听端口在代码中配置。所以,我需要从 wcf.config 中删除 ​​\<host>​​ 元素,然后在应用的 Main() 方法中添加如下的代码行:
builder.WebHost.UseNetTcp(8090);.

这应该在调用 ​​builder.Build()​​ 之前。

最后,我升级应用的 Main() 方法,添加配置到 ASP.NET Core 应用的依赖注入容器中。

builder.Services.AddServiceModelConfigurationManagerFile("wcf.config");

此时,应用将可以正常工作,客户端也可以成功连接到它。我还希望使 WSDL 也可以使用,所以,我继续对项目做一些修改。首先,添加如下代码到 Main() 方法中,来使得 ASP.NET Core 应用监听到端口 8080 ( 因为以前的应用从该端口下载 WSDL ):

builder.WebHost.ConfigureKestrel(options =>
{
options.ListenAnyIP(8080);
});

然后,当注册服务的时候,我添加对 ​​builder.Services.AddServiceModelMetadata()​​​ 的调用,来确保元数据服务可用,这样我将获得该 ​​ServiceMetadataBehavior​​ 对象实例,它以单例模式注册,通过修改它来使得 WSDL 可以下载。这些代码需要在构建 app 之后,但是在启动之前。

// Enable getting metadata/wsdl
var serviceMetadataBehavior = app.Services.GetRequiredService<ServiceMetadataBehavior>();
serviceMetadataBehavior.HttpGetEnabled = true;
serviceMetadataBehavior.HttpGetUrl = new Uri("http://localhost:8080/metadata");

通过这些修改,该 Bean Trader 服务现在完全迁移到了 .NET 6! 我可以运行该服务应用,并使用现在的客户端连接到它。并且 WSDL 也可以通过 localhost:8080/metadata 来下载。想要看到完整的本文中所有的修改,你可以 ​​查看该 PR​​,它这样修改了 Bean Trader 示例应用。最后,示例项目的 NetCore 文件夹中包含了只有 .NET Core 和面向 .NET 6 的项目!

翻译:使用 CoreWCF 升级 WCF 服务到 .NET 6_asp.net_05

总结

Bean Trader 示例项目只是一个小项目,但是希望该演练过程展示了在 .NET 6 平台上,使用 CoreWCF 来利用 WCF 服务继续工作做需要的修改。除了引用不同的命名空间之外,WCF 的服务实现几乎不需要修改,多数的 xml 配置也得以重用。我做了使得服务宿主创建的修改 ( 现在服务通过 ASP.NET Core 托管 ),但是我仍然能够重用以前用来定制服务宿主行为的代码。

举报

相关推荐

0 条评论