关于.NET Core是否应该支持WCF Hosting的争论
.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( "https://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( "https://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版本是可行的。
本文文字及图片出自 InfoQ
共有 1 条讨论