本文要点
本文试图回答“.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 版本是可行的。
原文链接:http://www.infoq.com/cn/articles/WCF-Net-Core-Debate
.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com