本文要点
- 本文试图回答“.NET Core 是否应该支持 Windows 通信基础(WCF) Hosting?”的问题;
- 支持者论据:许多工程师喜欢把 WCF 作为一种编程模型,不希望因为迁移到.NET Core 而产生(机会成本)开销;
- WCF 的优点包括严格基于契约的编程模型、灵活的端点和绑定、安全,等等,需要很少的管道代码;
- 反对者论据:WCF 和 ASP.NET WebAPI 及 REST 存在潜在的冗余,而且,WCF 经常需要采用非常复杂的方式实现;
- 创建服务器端 WCF 的投入是不值得的,应该优先考虑类似 SignalR 这样的工具。
.NET Core 是否应该支持 Windows 通信基础(WCF) Hosting?在许多人看来,这似乎是一个奇怪的问题;答案很明显……是?否?好吧,实际上,这个问题的正反双方都在为自己的立场激烈辩护。本文将分析这场争论,说明双方的论据。
争论变得如此激烈,以致于 WCF for .NET Core 项目成员 Barry Dorrans 不得不在 1 月份暂停了有关这个问题的辩论。我们将分析这场争论,从支持者的观点开始。
2016 年,Jan Johansson 发起了一个话题,让人们列出他们在使用而且希望出现在.NET Core 中的 WCF 特性。正如下面的汇总表所示,开发人员实际上正在使用 WCF 的许多高级特性。
- 事务性队列编程模型
- “ 行为(Behaviors)”
- “绑定(Bindings)”
- “上下文(Context)”
- 基于契约的编程模型
- 契约行为
- 基于契约的编码模型
- “发现(Discovery)”
- “持久化服务(Durable services)”
- “端点行为(Endpoint Behaviors)”
- “可扩展性(Extensibility)”
- 可扩展模型
- “头(Headers)”
- 实例管理
- 拦截模式管道
- 用于检测和访问 SOAP 头的消息查看器
- 元数据互换
- MEX 端点和 MEX 框架
- 命名管道
- Net.Pipe 绑定
- Net.TCP 绑定
- NetTcp(半双工)
- “操作行为(Operation Behaviors)”
- OperationContext
- 有序消息
- 队列服务
- 可靠性
- 安全性
- 使用 ServiceModel.ServiceHost 的自托管
- 服务行为
- System.Transactions
- 限流
注意,这些全都是 WS-* 或 WCF 特有的特性。例如,当他们说“可靠性”,他们实际上是说 WCF 支持 WS-ReliableMessaging 标准。
WCF 现状
许多人都有这样的印象,就是 WCF 仅用于遗留代码。但实际上,有许多公司在积极投资 WCF 软件开发。下面是一些例子。
Oliver C. Lanz 写道:
我举一个具体的业务案例,就是我们有一个有着几百万行代码的投资管理系统,服务器端目前托管在世界范围内大约 200 家保险公司和银行本地的 MS Windows Server 上。我们有大约 100+ 种服务类型,在最大的部署中,有大约 700 到 800 个并发服务实例在运行。我们的产品推动着核心业务的关键部分。
我们客户的 IT 支出非常高。这也是我们希望在未来几年做出重大改善的地方。其中一部分内容是找到托管环境的替代方案。一个比较好的选择是 Windows Nano 或.NET Core on Linux。为了能够采用.NET Core(或 Windows Nano),我们将失去 WCF 服务器端。
由于我们非常喜欢把 WCF 作为一种编程模型,我们无意重写我们的应用程序,除非将来的托管环境不再提供 WCF 服务器端。我们用了许多特殊的特性。要开始采用.NET Core,下面是一些重要的特性:
[…]
是的,我们会继续在.NET Core 上构建 WCF 服务。
Niplar 写道:
在过去的六年里,在我参与过的方案中(.NET 领域),我们总是基于 WCF 处理方案的服务层(位于防火墙 & 内部网后面)。没有东西能像 WCF 那样为我们提供同样的灵活性和对不同通信渠道的支持。
因为没有明确的 WCF 支持,所以我一直在阻止把生产环境迁移到.NET Core。如果.NET Core 不支持 WCF 服务器,我们就需要重写大量的基础设施代码;总之,最终是模拟 WCF 编程模型。
我参与过的最大的方案供 300 多家健康医疗机构使用,重写服务层和功能就是一项巨大的投资,就不用说面临的高风险了。
事实上,就是在那个方案中,我们曾希望找到一种方式,可以在新产品中统一服务器和嵌入式设备(Linux)的编程模型。在.NET Core 上支持 WCF 服务(不只是客户端)会给我们带来非常大的帮助和成本节省,因为那就不需要两个开发团队了;而代之以一个比较大的、非常专注的团队。
Fernando Ferreira Diniz de Moraes 写道:
我的情况和 [Oliver C. Lanz] 的非常相似,只是我的业务场景是销售网点系统。和他一样,我们把应用程序部署到世界各地的许多商店中。为了减少基础设施成本,我们也在寻找托管应用程序的替代方法。就像 [Jan Johansson] 所说的那样,随意部署 WCF 服务就很好,给我们带来了巨大的灵活性。
WCF 在我们的应用程序中扮演着重要的角色:它基于一个插件架构,其中的插件主要是 WCF 服务,因此,插件之间的通信实际上是 WCF 调用。这方面的改变意味着我们必须重写 / 重新构思许多基础设施代码。
在我们的情况下,使用 ServiceHost 实例的自托管和基于契约的编程模型至关重要。我们的计划是,不仅要迁移现有的服务,还要创建新服务。
Websitewill 补充道:
我做过许多利用 WCF 多方面特性的项目。我使用的大部分 WCF 特性(几乎一切)目前都从.NET Core 中消失了。许多缺失的功能需要各种第三方库(或大量的自定义代码)来填补,当 WCF 已经可以很好地发挥作用时,这个层面的投资是不值得的。最重要的一点是,WCF 极大地提高了我们团队的生产力。
目前,对我而言,最大的缺失是 WCF 提供的可扩展模型。
我的大部分项目都利用这个功能实现与其他组件(轻量级 WCF 服务)横切关注点的完全解耦。WCF 提供了一种极好的机制来实现这一点,不需要来自第三方的面向方面编程的库。开发人员不知道(甚或不关心),他们只需要专注于交付他们关心的特性的业务价值。
我们还使用 WCF 许多其他方面的特性,如:
复制代码
命名管道、事务性队列编程模型、严格(不是鼓励)基于接口的设计、安全特性、进程隔离、错误屏蔽,等等。如果.NET Core 不提供 WCF(或同等的功能),我就会损失太多的生产力,无法为这种切换辩护。如果一个可以用在任何环境的平台中包含所有这些强大的功能,那会很棒。想一下,WCF 的生产力加上更便宜的托管环境带来的成本节省。那是巨大的业务价值。
Pavel Dvorak 甚至说 WCF 是他们使用.NET 的原因:
完全支持在.NET Core 包含服务器端“WCF”的观点。我们刚刚完成了另一个相当大的、几乎完全是服务器端的处理系统。起初,我们因为没有使用 Microsoft/.NET 承受了巨大的压力,主要是因为其他(开源)技术栈在用于“基于微服务的”(就像传统的 Web 服务)解决方案时所具备的相对优势。但是,WCF 的优点,如严格基于契约的编程模型,特别是命名管道绑定,端点和绑定的灵活性(是的,声明式方法 / 可配置性是一个优势),安全性,工具如日志的可扩展性,在系统增长,需要扩展性、性能及可维护性时,这些优势非常关键,而且,管道代码真得非常少。很明显,下一步是恰当的容器化(我们一直等待 Nano Server),总之,能够把系统移植到下一代运行时平台,而又不会对当前的质量造成任何损失。
在话题“Server side WCF #1200”中,你可以看到更多开发人员支持使用 WCF 开发的例子。
为什么最初不包含 WCF Hosting?
和以前一样,一个答案是,那是个简单的人力问题。只有这么多开发人员,他们不可能什么都做。来自微软的 Ron Cain 解释说:
郑重声明,我们不是故意把缺失的.NET Framework WCF 特性排除在.NET Core WCF 之外。不如说,最初的目标是,在处理其他 WCF 关键任务特性之前,在.NET Core 中支持所有现有的 Windows Store WCF API(都是面向客户端的)的特性。为了让它可以跨平台,移植 WCF 的许多工作都涉及重新实现 WCF 所依赖的 OS 级库(如套接字层、加密等),或许,这有助于我们理解现状。因此,支持 WCF 特性通常要首先针对每个平台替换 OS 级的库。这也许有助于理解.NET Core 不再提供 WCF 中的“W”。
这就是为什么从你那里听到什么特性最重要如此有价值的一个原因,因为那让我们可以更深入地探讨这样的问题,“在 Linux 上实现特性 X 需要什么库?在 OS X 上呢?”等等。请继续提出建议和具体的方案!
为什么不使用 REST?
对于 WCF,最常见的抱怨是它与 ASP.NET WebAPI 和 REST 存在冗余关系。对此,Jörg Lang 回应道:
服务之间的消息很重要,在开发企业后端时,REST 不会奏效。它缺少太多其他人提到的东西。因此,.NET Core 当然应该支持事务、队列消息、命名管道、可扩展性。
因此,.NET Core 必须以这种或另外一种方式提供那些东西。如果把它叫做 WCF,我也不介意。也许,这是个修复某些 WCF 弱点的机会,如过于复杂的配置,代之以基于惯例的方法。
除了 MSMQ 或服务总线外,你还应该 / 必须支持其他消息框架。一般来说,支持 AMQP 应该会不错,包括各种消息模式。
Agustin M Rodriguez 附和了那种想法:
WCF 一直用于提供高质量可扩展的服务,利用跨网络事务(System.Transactions)提供可靠性。如果.NET Core 不支持 WCF,那么我们会失去太多通过广泛的 WCF 拦截器链获得的“免费”益处,包括日志、行为和上下文流。
在 Scott Hurlbert 看来,WCF 的吸引力是它根本不需要使用 HTTP:
这两行代码只是一个例子,但是,有趣的是,这里的 Binding 和端点模式是组件:
复制代码
Binding binding = new BasicHttpBinding(); IMySimplestService proxy = ChannelFactory<IMySimplestService>.CreateChannel(binding, new EndpointAddress( "http://localhost:8008/" ) ); proxy.Echo("Hello");这很有趣,因为那意味着,通过交换那些来自 WCF 的组件可以实现通过 Http/https、UDP、TCP-IP、MSMQ、NetPipes 及其他一些协议和端点模式通信。
按照我的理解,在近来的 Web 开发中,许多人已经忘记了 HTTP 之外的其他东西,但是,如果你的应用增长,那么你可能会发现自己希望有能力使用完全相同的代码,但是指向一个队列的端点。令人遗憾的是,大多数其他的框架会让用户自己重新实现队列系统,而不仅仅是重定向它。
更别提事务(也已淡出了视线——直到它们必不可少)和各种形式的身份验证和加密等等特性了。
Catalin Pop 同样关注 WCF 如何成为各种协议之上的抽象:
是的,有许许多多的框架,大的,小的,更“企业级的”或者更面向 1337 h4x0r 的,提供不同的选项和模式,有的严格,有的灵活……这就是问题所在……没有基线。
WCF 应该帮助处理所有这些完全不同的选项,提供一种统一而抽象的通信框架,作为.NET 开发的基线。
你希望使用二进制 protocolX,而不是 http,当然,你可以插入它。你希望使用 Oauth2,而不是 windows 验证,当然,配置一个,你希望使用 NServiceBus 插入 NServiceBus 绑定。你希望以某种形式转换上下文,如网络事务范围,你也可以把那个插入。应用程序编程模型保持不变。
从.NET 应用程序的角度来看,RPC 本身并不是一个复杂的东西,你调用一个方法或者接收一个调用。使其变得复杂的是众多方法和框架,以及你可以在其中实现的安全性、格式、特性和其他选项。
这些地方应该引入 WCF,那是 WCF 的长项。
“WCF 太复杂”
对于 WCF,一种常见的批评是太复杂。公平地讲,它经常以一种非常复杂的方式实现。但是,就像 Scott Hurlbert 所指出的那样,不一定必须那样。下面是一个完整的 WCF 客户端和服务器所需的代码。
这是一个 ENTIRE Wcf 服务:
复制代码
[ServiceBehavior] public class MySimplestService : IMySimplestService { public string Echo( string pInput ) { return $"I heard you say: {pInput}"; } }这是接口:
复制代码
[ServiceContract] public interface IMySimplestService { [OperationContract] string Echo( string pInput ); }好吧,也许托管这个服务很难。不。下面是服务托管和调用。这是全部的代码:
复制代码
var myServ = InProcFactory.CreateInstance<MySimplestService, IMySimplestService>(); Console.WriteLine( myServ.Echo("Hello World") );只是还没有达到企业级的质量,而且很简单。
我认为,WCF 已经获得了一个奇怪的坏名声,因为人们以一种难以置信的复杂方式实现它。不管你信不信,对于.NET,这就是网络两端所需的全部。借助来自 iDesign 的 ServiceModelEx 框架,你甚至可以动态构建一个代理:
复制代码
Binding binding = new BasicHttpBinding(); IMySimplestService proxy = ChannelFactory<IMySimplestService>.CreateChannel( binding, new EndpointAddress( "http://localhost:8008/" ) ); proxy.Echo("Hello");严格来说,那四行代码(来自包含结构代码在内的 17 行代码里)创建了一个企业级服务,它是代理,进行服务调用。它没老化,那是生产力。
注意,甚至是这其实都比你需要的东西多。如果你在使用一个代理生成器,那么服务类可以作为自己的服务契约,而不需要一个单独的接口。
反对 WCF 的机会成本论据
Blake Niemyjski 总结了反对 WCF 的真正理由:机会成本和过去糟糕的体验:
我认为,创建服务器端 WCF 的投入是不值得的,应该优先考虑类似 SignalR 这样的工具。WCF 客户端配置总是那么困难,我讨厌它:(,如果我错了,请帮我纠正……但是,为什么 Web API 不是要选择的方法……它是轻量级的,而且能给你构建应用所需要的所有东西,从任何平台只需要一个简单的调用即可……
把安全、事务、发布 / 订阅留给实现者……
还有其他几位开发人员也赞同“WCF 与 VB.NET”不值得投入。(这些争论似乎把 WCF 和 VB.NET 看作是相同的主题。)不过,Catalin Pop 不同意这种观点:
[把安全、事务、发布 / 订阅留给实现者……] 是任何人都能给出的最糟糕的建议。安全永远不应该留给实现者,那从来都是最糟糕的安全漏洞的源头……安全专家真得很少,或者说,很少有开发人员有能力恰当地实现安全细节,这项工作是由不足 1% 的程序员完成的。
服务器端 WCF 情况如何?
早在去年 6 月,Jeffrey T. Fritz 写道:
有非常多的是 WCF 团队,我们正致力于开发可以确保兼容 Windows 10、Windows Server 和 Windows 容器的特性。
在 Build 大会上,我们做了一次非常成功的演示,第一次展示了我们的 Windows 容器。该领域的工作还在进行中,我们计划继续这些领域的投入。
WCF for .NET Core 是我们重点关注的,我们正在和 ASP.NET Core 团队合作,优先进行这项工作。在可以公开发布的时候,我们会分享更多细节。
虽然 WCF 所需的部分底层库已经移植到了.NET Core,并且 / 或者添加到了.NET Stardard,但是,WCF Hosting 本身并没有实际的进展。在 3 月份,一个题为“请做决定:服务器端WCF ”的独立话题被创建,并且打上了.NET 3.0 里程碑的标签。
特别是最近,Immo Landwerth 写道,“我们不会在.NET Core 3.0 的时间框内引入[……]WCF Hosting,但是,我们稍后会根据用户的反馈来做。”
GitHub 提供了 WCF 的源代码,遵循 MIT 开源许可协议。因此,理论上讲,由社区支持的 WCF for .NET Core 版本是可行的。
评论