翻译:使用 CoreWCF 升级 WCF 服务到 .NET 6
翻译:使用 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 的过程还是有用的。
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
该工具随即指导我进行一系列的升级步骤 ( 这会通过升级助理自动处理 ),如下所示:
我通过升级助理的完整步骤如下:
选择入口点。这支持我选择希望运行在 .NET 6 上的项目。基于该选择,升级助理将决定要升级的项目以及升级的次序。我选择
BeanTraderServer
选择一个项目进行升级。这过渡到该工具开始升级指定项目。它建议我先升级
BeanTraderCommon
项目,然后升级beanTraderServer
项目更加合理,所以我选择该升级顺序。备份
BeanTraderCommon
将
BeanTraderCommon
项目转换为 SDK 风格的项目升级
BeanTraderCommon
的 NuGet 包。该步骤替换对 System.ServiceModel 程序集的引用,使用 NuGet 包,例如 System.ServiceModel.NetTcp 来代替。升级
BeanTraderCommon
的目标架构 ( TFM )。该工具建议使用 .NET Standard 2.0,因为该项目是一个纯类库项目,没有任何 .NET 6 特定依赖。此时,对辅助项目的升级已经完成,升级助理切换到升级
BeanTraderServer
备份
BeanTraderServer
转换
BeanTraderServer
项目到 SDK 风格将 System.ServiceMoel 引用替换为等价的 NuGet 包,如在
BeanTraderCommon
项目中一样升级
BeanTraderServer
项目的目标框架。工具建议为 .NET 6,因为该项目是控制台应用禁用不再支持的配置节。升级助理检测到
BeanTraderServer
在它的 app.config 文件中有一个system.ServiceModel
配置节,它不再被 .NET 6 所支持 ( 会导致运行时错误 ),所以它为我注释掉了。最后,我们将会在其它文件中重用这段注释掉的配置节,来配置我们的 CoreWCF 服务。在检查 C# 源是否有任何必要的更改时,升级助手会发出有关 WCF 使用情况的警告。警告消息提醒我,BeanTraderServer 使用服务器端 WCF API,这些 API 在 .NET 6 上不受支持,并且该工具未进行升级。它告诉我,我需要手动进行更改,并建议升级到 CoreWCF、gRPC 或 ASP.NET Core。
清理升级。此刻,升级助理完成工作,所以它删除一些临时文件并退出。
3.2 CoreWCF 迁移
现在升级助理已经完成了升级过程,是时候升级 CoreWCF 了。在 Visual Studio 中打开 Bean Trader 解决方案,我发现 BeanTraderCommon 类库可以成功构建。项目升级到 .NET Standard 已经完成了。而 BeanTraderServer
项目有一些错误,可以想到,关联到不能找到某些 WCF 类型。
为了开始升级到 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
做一些如下的修改:
IMetadataExchange
还不被 CoreWCF 支持,所以删除 mex 端点。我可以仍然使得 WSDL 可以被下载,记住,我随后将展示如何做到这一点。在服务模型配置中,元素
\<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 的项目!
总结
Bean Trader 示例项目只是一个小项目,但是希望该演练过程展示了在 .NET 6 平台上,使用 CoreWCF 来利用 WCF 服务继续工作做需要的修改。除了引用不同的命名空间之外,WCF 的服务实现几乎不需要修改,多数的 xml 配置也得以重用。我做了使得服务宿主创建的修改 ( 现在服务通过 ASP.NET Core 托管 ),但是我仍然能够重用以前用来定制服务宿主行为的代码。
翻译:使用 CoreWCF 升级 WCF 服务到 .NET 6的更多相关文章
- 关于已部署的WCF服务升级的问题
在日常的开发过程中,我们会经常迭代发布不同的版本,所以WCF服务的接口也会经常处于变动的状态,比如在传递实体类中新加一个字段.修改参数名称等等关于服务升级的问题.但是我们不可能让已发布的版本重新引用新 ...
- 如何使用花生壳 发布WCF服务 进行外网访问
当我们发布WCF服务的时候,可以直接通过服务器的域名或者IP进行. 但是如果仅仅是通过花生壳进行域名解析,需要我们自己在设置的时候注意以下几点, 直接用图说明问题 1.首先配置花生壳,在红色处填写一个 ...
- IIS发布WCF服务项目之本地
最近由于项目需求,要做一个上传文件附件的功能,由于是多用户访问,所以这就用到了WCF服务,程序编写完成就需要发布了, 下面记录下发布到IIS的过程: 1,安装IIS 第一步:检查Windows7中II ...
- Azure开发者任务之七:在Azure托管服务中托管WCF服务角色
在一个托管服务中托管一个WCF服务角色和托管一个ASP.Net Web Role基本类似. 在上一篇文章中,我们学习了如何使用WCF Service Web Role. 在本文中,我会对上一篇文章进行 ...
- 创建WCF服务寄宿到IIS
一.WCF简介: Windows Communication Foundation(WCF)是由微软开发的一系列支持数据通信的应用程序框架,可以翻译为Windows 通讯开发平台. 整合了原有的win ...
- IIS8中部署WCF服务出错:HTTP 错误 404.3 - Not Found
解决方法,以管理员身份进入命令行模式,运行: "%windir%\Microsoft.NET\Framework\v3.0\Windows Communication Foundation\ ...
- WCF服务上应用protobuf
WCF服务上应用protobuf Web api 主要功能: 支持基于Http verb (GET, POST, PUT, DELETE)的CRUD (create, retrieve, updat ...
- WCF服务寄宿到IIS
一.WCF简介: Windows Communication Foundation(WCF)是由微软开发的一系列支持数据通信的应用程序框架,可以翻译为Windows 通讯开发平台.整合了原有的wind ...
- 如何建立一个WCF服务并将其发布到IIS上
在我们的软件开发中,经常会连接到数据库中,如果是常规的操作,我们经常会将连接数据库的字符串写在配置文件中,然后去读取数据库的连接字符串,其实这种方式是非常不科学的,这会直接暴露我们的数据库,直接暴露我 ...
随机推荐
- memcached 是原子的吗?
所有的被发送到 memcached 的单个命令是完全原子的.如果您针对同一份数据 同时发送了一个 set 命令和一个 get 命令,它们不会影响对方.它们将被串行化. 先后执行.即使在多线程模式,所有 ...
- python udp socket通信
前段时间学习了一下c++的socket通信,但发现那玩意儿比较复杂还是转向python了,下面就是一个简单的udpsocket通信程序,欢迎大佬前来指正 udp聊天 import socket # 创 ...
- xacro 语法总结
xacro是为了解决在编写urdf文件过程中,出现的标签内容重复,但又不得不去写.一些值的计算有依赖的问题.为了和urdf文件区分,我们定义的模型文件名后缀为.xacro. 从功能的角度来说,xacr ...
- 记一些css 3效果
半透明边框 background-clip: 规定背景的绘制区域 .div { width: 200px; height: 200px; background: blue; border: 10px ...
- 1kb 的 placeholder.js 增加 img 标签使用方式
预览 官方网站示例. 项目 github 地址 使用 引入 placeholder.js 到你的前段代码中: <script src="placeholder.js"> ...
- React+dva+webpack+antd-mobile 实战分享(二)
第一篇 https://segmentfault.com/a/11... 在上一篇文章中教给大家了怎么搭建项目的架子:那么今天我们就来说一下项目里的导航和列表的实现 导航 废话不说啦 下面直接给大家讲 ...
- python-汇率兑换
按照1美元=6人民币的汇率编写一个美元和人民币的双向兑换程序 输入格式: 输入人民币或美元的金额,人民币格式如:R100,美元格式如:$100 输出格式: 输出经过汇率计算的美元或人民币的金额,格式与 ...
- 微信小程序animation动画2种方法
这里介绍 2 种方法一种是常规的小程序方法操作,另一种是引入动画库 1. 常规动画操作设置 wxml: <view> <view bindtap="clickMe" ...
- Vue UI 可视化项目管理界面
除了直接使用npm的命令进行安装脚手架的安装以外,我们还可以使用Vue提供的GUI方法vue ui来进行项目的构建以及安装 win+R powershell 打开终端 在一个干净的目录下输入命令 vu ...
- Java中最早期的集合Vector
1.Vector类可以实现可增长的对象数组.与数组一样,它包含可以使用整数索引进行访问的组件.但是,Vector 的大小可以根据需要增大或缩小,以适应创建 Vector 后进行添加或移除项的操作. 2 ...