也许有读者会说,为什么要谈 WCF?近期不是 Web API 比较热门?在这个手机、Devices 当道的现在,究竟有什么地方会需要使用到 WCF 呢?
的确,现在访间你能找到的课程,或者您可能参与某项目的实践 (网页应用程序、手机 APP 也好),你需要的通常也都是提供 Services 层,而这个 Services 层通常也就是 Web API。那么,难道 WCF 就无用武之地?其实也不是,看什么情况用什么技术,有一些地方是 Web API 无法做到的
前言
也许有读者会说,为什么要谈 WCF?近期不是 Web API 比较热门?在这个手机、Devices 当道的现在,究竟有什么地方会需要使用到 WCF 呢?
的确,现在访间你能找到的课程,或者您可能参与某项目的实践 (网页应用程序、手机 APP 也好),你需要的通常也都是提供 Services 层,而这个 Services 层通常也就是 Web API。那么,难道 WCF 就无用武之地?其实也不是,看什么情况用什么技术,有一些地方是 Web API 无法做到的,比如:
当你需要开发的是企业内部分散式系统软件组件,而且还需要跨机器做事务,甚至你想要在服务端模拟类似软件 Load Balance 的效果 (让你设定消息的 Filter 方式),这在 WCF 里有 Routing Services 可以透过内建的 Message Filter 可以做到类似的效果,又或者您要跟 MSMQ 之间轻易的整合,这些都是 Web API 所做不到的。
或者可以这样说,对外走轻量 JSON 的 Services 大部分以 Web API 为主,对内的系统较无平宽限制,刚好是 WCF 可以发挥的领域。
大纲
一、WCF 程序设计对象模型
二、建立与装载 WCF 的几种方式
三、建立服务合约与数据合约
四、如何维护 WCF 数据状态与 支持分散式的事务?
五、如何在 WCF 中实践消息加密、验证、授权?
六、如何设计支持 MSMQ 的 WCF 应用程序?
七、如何设计良好性能的 WCF 服务?
下面我们开始今天要为大家谈的内容,首先
一、WCF 程序设计对象模型
因为 WCF 也是 .NET 应用程序一种,要了解 WCF 的对象模型前,我们得先了解 .NET CLR 的模型与.NET应用程序定义域。
图(一)、WCF 的 Hosting 的应用程序模型
虽然.NET 应用程序也是以 Win32 Process Model 中,但古子里大不相同!一个处理序 Process 可以有多个 Application Domain ,一个 Application Domain 又可以有多个 ServiceHost,如上图,应用程序定义域是 .NET CLR 用来隔离 Managed 程序与 Windows 的方法,处理序与应用程序定义域之间的关系,很像应用程序及应用程序定义域与 WCF ServiceHost 之间的关系,而且每个应用程序定义域可以装载零个或多个 WCF ServiceHost 执行个体
注:另外WCF 要求必须在 Windows 处理序内至少装载一个应用程序定义域
The ABC of WCF
我们可以透过下面这张图,快速地来了解 WCF
图(二)、The ABC of WCF
下面我们再来看一张图,这一张图会说明 WCF 中从 Messaging 层到 Service Runtime 的服务推叠。
图(三)、WCF 的服务栈
由图中可以看出 Service Runtime 可以可程序化 Metadata Behavior、Error Behavior 与 Transaction Behavior 等,Application 端需要透过 Contract 与 Service Runtime 沟通,Messaging 层则管理关于消息的权限 (验证/授权) & 可延展性 & 自订通道 (Channels)、通道 Channels 传递的消息支持加密 (text, binary, MTOT, XML) 与通道支持通讯协定 (TCP, HTTP)等等。
最下面的 Activation and Hosting 则是 WCF 可以 Hosting 的种类。
而使用 WCF 进行通讯时,您必须选定一种 Binding ,在图(二)中,我们知道 Binding 是用来是用来辨识服务通讯的传输,格式以及通讯协定,下面列表为 WCF 4.0 所支持的 Binding 种类,(并未全部列出)
图(四)、WCF 的 Binding 种类
二、建立与装载 WCF 的几种方式
一般来说,建立与装载 WCF 有下面的几种方式:
- Windows Forms 应用程序
不管使用 Windows Form、Console Application、Win32 Services 都可使用自主挂载方式
自主挂载范例程序如下:
Uri baseAddress = new Uri(string.Format("http://localhost:{0}/ScheduleJobService", TcpPort));
ServiceHost WcfHost = new ServiceHost(typeof(ScheduleJobWcfService), baseAddress);
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
WcfHost.Description.Behaviors.Add(smb);
//启动 WCF 服务
WcfHost.Open();
- Console Application 主控台应用程序
Console 挂载方式与上面 Windows Form 相同
- Windows Service 服务应用程序
挂载方式与上面 Windows Form 相同,而自主挂载 (ServiceHost) [优点]如下:
- 易于使用:只需几行程序就能让您的服务正常执行
- 具有弹性:您可以透过 ServiceHost 的 Open() 和 Close()
- 易于侦错:对装载于自主装载环境的 WCF 服务进行侦错,可让您以熟悉的方式侦错,而不必附挂在别的应用程序中来启动服务
- 易于部署:一般而言,部署简单的 Windows 应用程序,就跟使用 xcopy 一样容易。您不需要类似伺服数组上的任何复杂部署,即可将简单的 Windows 应用程序部署为 WCF ServiceHost
- 支持所有的系结和传输:自主装载完全不会局限在现成的系结和传输,在 Windows Server 2003 上的 IIS 6.0 则限制只能使用 HTTP,Server 2008/2012 只要系结 net.tcp 协定即可
但自主挂载 (ServiceHost) 也不是没有缺点:
- 有限的可用性:只有当应用程序正在执行时,才能连上服务
- 有限的功能:自主装载的应用程序对于高可用性、便利管理能力、强固性、恢复能力、版本控制和部署案例,仅提供有限的支持。别的不说,至少默认配置下的 WCF 就不提供这些支持,所以在自主装载的 ServiceHost,您必须自行实践这些功能;比如拿 IIS 来说,在 AppPool 里便提供许多进阶功能
- Internet Information Services (IIS) 的 ASP.NET 应用程序
通常,只需使用传统 ASP.NET Web 导向的服务 HTTP 可满足需求,在 IIS 上装载 WCF 服务时,WCF 服务可以享用 ASP.NET 应用程序集区 AppPool 的所有功能。
图(五)、IIS 管理员
- 在 IIS 7.0 以上提供的 WAS 内部的 WCF 服务
这里要注意的是,Windows Server 2008/IIS 7.0 以上不需要再安装 WSE 直接支持 WS-* 安全性规格,像是 WS-Security、WS-Trust 和 WS-SecureConversation,WAS (Windows Process Activation Service) 它让IIS可以支持非 HTTP, HTTPS 的协定的服务载体。
图(六)、开启关闭Windows功能
图(七)、IIS 7 以上安装 HTTP 启用后支持TCP
所谓的 WS-* 规格
所谓的 WS-* 规格是为了 Web Service 的安全性与互通性所发展而来的规格定义,像其中 WS-Security 规格定义了 Web Service 如何在安全方式下沟通、WS-Transactions 指定了如何在跨不同的 Web Service 的集合中实践事务,以及 WS-RelibleMessaging 描述在分散式应用系统环境中,如有网络断线、组件失效的情况下却能确保消息传递是有效的 (微软应用情境如:MSMQ)。
为确保 Web Service 的互通性,应建立符合这些规格的 Web Service 。
三、建立服务合约与数据合约
Service Contract:
所谓的 Service Contract 服务合约是用来定义服务中可以使用的 operation,描述每个 operation 内的参数、回传的类型,程序开发人员可以使用这些资讯来建立用户端应用程序,用户端程序开发人员则可使用 svcutil.exe 公用程序从服务的 WSDL 描述档来产生 proxy 类,再使用这个 proxy 类跟服务端通讯
Service Contract 应不依赖发送消息所使用的通讯机制,但 SOAP 消息依赖 Service Contract ,若 Service Contract 变更,用户端也必须更新为新的版本,否则传递的消息可能让服务端看不懂或是无法正确处里消息。
Data Contract:
定义服务端与用户端传递的数据格式、类型,但各平台可能都有些复杂的类型,像是类、结构 (Structure)、枚举类型 (Enumeration) 等,需要由服务端来指定用户端该如何封装与传递指定的格式到服务器中,Data Contract 会包含在用户端以 svcutil.exe 公用程序产生的 proxy 中。
Service Contract 服务端的版本控制
不要认为变更服务是个简单的工作,而且尽可能减少用户端的变更,并花一点时间在相容用户端现有程序、检查用户端的功能无误。
并且了解什么是破坏性变更,一般来说当服务端有破坏性变更时,避免在这个时候回传详细错误消息,因为恶意攻击者可以透过它查探进一步的资讯。
C# 的 overloading 无法在 SOAP 标准中使用
[OperationContract(Name = “GetListProdcts”, …)]
List GetProducts();
何谓 Service Contract 的破坏性变更
底下列一张表格给各位参考:
Data Contract 相容性
在相容性部分,如果您需要维持原有用户端应用程序相容性,DataMember 属性提供两种可用的属性:
1. IsRequired:
如果设定为 True,服务所接受的 SOAP 消息必须要在 DataMember 中包含其值,这个属性默认值为 False,所以默认会为每个遗漏的字段产生默认值
2. EmitDefaultValue:
若设为 True,如果字段直没有包含在用户端传送过来的 SOAP 消息里,用户端的 WCF Runtime 会为这个遗漏的字段产生默认值。该字段默认值为True
重新产生 proxy 类,更新用户端应用程序
这有几种方式,
- 从工具 Visual Studio 中重新产生
图(八)、从 VS 中产生 Proxy 类
- 使用 svcutil.exe 来产生
1. 从执行中服务或线上中继数据文档产生用户端程序
svcutil http://service/metadataEndpoint
2. 从执行中服务下载中继数据文档
svcutil /t:metadata http://service/metadataEndpoint
3. 针对服务合约以及组件中关联的类型产生中继数据文档
svcutil myAssembly.dll
4. 从本机中继数据文档产生用户端程序
svcutil *.wsdl *.xsd /language:C#
四、如何维护 WCF 数据状态与 支持分散式的事务?
我们先来谈谈 WCF 的状态维护部分,因为这与能否事务有绝对关系,WCF Runtime 提供了 3 种执行个体内容模式:
- InstanceContextMode.PerSession
PerSession 的状态从 Client 任意调用一个 operation 之后开始,直到 Client 的 proxy 结束后结束,类似工作阶段概念,每一个 Client 在Server上都有独立、互不互相干扰的执行个体
- InstanceContextMode.PerCall
如同 ASP.NET WebForm & MVC Controller 一样是by request建立执行个体,用完即丢,不保留任何状态 (Stateless)
- InstanceContextMode.Single
与 SingleCall 相同,但要注意的是,它是单一线程,除非您设定为 ConcurrencyMode.Mutiple 模式,否则 Client 端的下一个 operation 的调用必须等待上一个 operation 完成才会执行。
另外,WCF 的 Session的定义是从 Client 端 new WcfProxyClient() 开始,一直到它在前端被.Close()结束或 Dispose() 被回收为止
且要启用Session需选用
- Ws*Binding
- NetTcpBinding
- NetNamedPipeBinding
- …
注:BasicHttpBinding 不支持
还有要注意,即使您将 ConcurrencyMode 设为 Single,他的确会限制执行个体一次以一个线程执行服务,但最好是设定 MaxConcurrentCalls 为 1,以确保没有次序不对的问题,可是当 ConcurrencyMode 为 Reentrant 时,对外部调用使用 Begin/End 异步调用模式会触发例外状况,异步传出调用需要 ConcurrencyMode 为 Multiple ,而在该情况下,您必须处理同步处理问题。
一般来说,如果违反其并行模式的执行个体有消息到达,该消息会等到执行个体可供使用为止,或等到它逾时为止。
常见的作法,使用 lock 关键字以确保只有一个线程进入,如下图:
图(九)、使用 lock 关键字以确保只有一个线程进入
如何实践支持事务的 WCF 应用程序?
一般来说,官方建议使用 TransactionScope 来实践事务,您可以在 operation 上声明 OperationBehavior 属性中的 TransactionScopeRequired 属性为True来初始化事务,然后 operation 可以使用 CommitableTransaction 来启动事务或是由用户端来启用事务,不过在 WCF 的用户端应用程序中,建议使用 TransactionScope对象来建立事务。
以及您必须使用 PerSession 执行个体内容模式,因为WCF必须在Operation与调用者间维护事务状态,除非将 TransactionAutoComplete 设为 true,另外也不支持在事务的 WCF 使用单向 (one-way) 的 Operation。
WCF 在 ServiceBehaviorAttribute 中提供额外的两个属性让您设定:
- ReleaseServiceInstanceOnTransacationComplete:(默认为True)
By default 服务在每个事务结束之后会强制回收服务执行个体,如果用户端调用其他的 operation,它必须产生新的执行个体来服务事务
- TransactionAutoCompleteOnSessionClose:(默认为False)
当工作阶段完成时,WCF Runtime 会自动完成目前的事务
接着,透过下面范例来看如何撰写支持事务的 WCF Service
图(十)、范例程序
如果您需要做的异质平台间的事务,WCF 口已透过使用 WS-Atomic Transaction (WS-AT) 协定来实践支持异质(heterogeneous)环境、分散式事务。
首先
1. 您必须启用WS-AT 组态公用程序来设定 (WS-AT) 支持
图(十一)、启用 WS-Atomic Transaction (WS-AT)
注意:这里必须以 32位来执行MMC
2. 设定两部电脑间的信任关系
WS-AT 通讯协定服务需要系统管理员明确授权个别账户,才能参与分散式事务
步骤如下:
- 使用 makecert.exe 公用程序建立暂时性凭证
makecert -n “CN=RootCaClientTest" -r -sv RootCaClientTest.pvk RootCaClientTest.cer
- 将这些凭证安装到适当的凭证存放区,再使用 wsatConfig.exe 工具将每部电脑的凭证新增至授权之参与者凭证清单中
五、如何在 WCF 中实践消息加密、验证、授权?
这里要跟大家探讨如何保护企业 WCF Service?这里会有几个安全性议题需要讨论,这里先谈使用者验证
所谓的验证:
- 维护用户端应用程序和服务间通讯的机密性 (Confidentiality)
- 举例来说,有心人士可以利用软件或硬件的TCP/UDP封包分析器以拦截可能包含私人金融卡帐密或是机密的个人资讯
- 防止被窜改或有错误的消息
- 就算有消息保密还是难防有心人士拦截后再送往目的地时破坏信息内容,因此您可以利用杂凑(hash)或是XML Signature签章来侦测消息是否遭到窜改
- 确认消息能够正确的传送
- 即使消息没有窜改也可能遭拦截重复发送,可以使用时间注记是否超出合理时间限制,如超过就丢弃它
- 防止假冒的服务
- 如钓鱼网站。防范方式可以使用凭证 (双向验证)
常见的验证方式如下:
常见的验证方式
- 使用 Windows 验证 (AD)
- 或者透过 Kerberos 协定来识别使用者,但只能在 Windows 网域(Domain)中使用
- 自订验证方式、Form 验证、Cookie 验证等等
- 使用 SQL Membership Provider 进行验证
- 使用凭证
- 使用凭证验证用户身份
- SSL 双向验证 (Trust)
还有,也可以透过实践消息的安全性来加密传输的数据,WCF 也有内建的算法 SecurityAlgorithmSuite 可以做这件事。
常见的方式如:
- 使用 SSL (Secure Socket Layer) 加密传输数据
- 透过CA取得公钥(Public)、私钥(Private)
- 使用算法(如:SecurityAlgorithmSuite)加密消息内容,WCF 具备三种常见安全性模式:
-
- Message:系统会使用 SOAP 消息安全性来提供安全性
- Transport:安全性可使用安全性传输 (例如,HTTPS) 来提供
- TransportWithMessageCredential:传输、消息与“使用消息认证进行传输”
注意:不是所有系结都支持都支持上面三种模式
使用 Windows 验证 (AD)
图(十二)
在服务端的 config 加入如下:
图(十三)
使用如下程序:
图(十四)
自订验证方式、Form 验证、Cookie 验证
图(十五)、自订验证的 Cookie 票卷做法
接着撰写 Login 验证的方法,检核帐密无误后,产生Cookie 票券
图(十六)
使用 SQL Membership Provider 进行验证
在 web.config 或是 app.config 上按鼠标右键,选择使用‘编辑 WCF 组态’,然后点开‘进阶’底下的‘服务行为’,在‘(空白名称)’上面再点鼠标右键,选择‘新增服务行为延伸’,如下图所示。
图(十七)、新增服务行为延伸
图(十八)、新增行为元素延伸区段
然后设定验证模式为 ‘UseAspNetRoles’,在设定角色提供者为‘AspNetSqlRoleProvider’
图(十九)、设定 serviceAuthorization 的 PrincipalPermissionMode
图(二十)、设定 serviceCredentials 的 MemberShip 提供者 与 使用的验证凭证模式
再将 roleManager 设定为 enabled
图(二十一)
记得最后要设好连线字符串
图(二十二)
使用凭证验证用户身份
如何在 WCF 中使用凭证来验证身份呢?
1. 可使用 Makecert.exe 建立暂时性凭证
Makecert –sr CurrentUser –ss My –n CN=Alice –sky exchange
2. 设定 Binding 的 SecurityMode 为 Message
图(二十三)
3. 设定 serviceBehaviors 的 behavior 的 serviceCredentials 底下的 authentication 属性
图(二十四)
4. 撰写如下用户端程序即可调用
图(二十五)
六、如何设计支持 MSMQ 的 WCF 应用程序?
在设计 MSMQ 的 WCF 应用程序之前,我们先来了解什么是 MSMQ?
何谓 MSMQ
图(二十六)
MSMQ 是 (Microsoft Message Queue)的缩写,它是 Windows 的随附选用组件,可透过新增 Windows 功能公安装,如下图。
图(二十七)
MSMQ 队列管理员会实践可靠消息传输通讯协定,使消息不会在传输期间因为网络瞬断遗失,且 MSMQ 中,队列可以为事务式或非事务式,WCF netMsmqBinding 提供与队列系结以便与 MSMQ 进行通讯。
MSMQ 的适用情境
- 任务性的传输,强调可靠性,比如金流服务、电子商务等等
- 异步传输,如:嵌入式和手持式设备等应用
- 强调系统间松散的耦合,有了彼此沟通的方式(队列),使的各系统升级变得简单
- 网络急剧不稳定的传输需求,MSMQ 可在网络可通讯时才传输,在可靠传输的通讯下,可确保消息正确送达,也不会因为网络瞬断而丢失消息
由于 WCF 本身有合约会指定要交换的项目,而且系结中会指定用来交换消息 (或“如何交换”) 的机制 (Binding),所以一般来说,WCF 非常适合拿来设计队列 MSMQ 的应用程序。
在 WCF 中使用 netMsmqBinding 队列系结有以下几点必须注意:
- 所有服务作业必须为单向,因为 WCF 中的默认队列系结不支持使用队列的双工通讯
- 使用队列系结,使用至少需要使用 WCF 内建的 netMsmqBinding 设定系结,而且要设定消息队列 (MSMQ)
- 为了让用户端方便使用,服务上最好有额外的 HTTP 端点 (mex),让中继数据可以直接经过查询取得相关 proxy 资讯
图(二十八)、设计支持 MSMQ 的 WCF 应用程序
测试结果
图(二十九)
七、如何设计良好性能的 WCF 服务?
WCF 中提供了一种服务结流 (throttling) 方式来控制资源的使用,以免服务被过度的消费,要设计出良好性能的 WCF 应用程序之前,我们先来了解什么是服务节流 (throttling)?
服务节流概论
服务节流(throttling) 是用来来控制资源的使用,当ChannelDispatcher对象在找寻合适的operation的时候,还可以检视目前的需求是否超过负荷,若超过会先放置在内建的 Queue 中。在 ChannelDispatcher 有一个对象叫做 ServiceThrottle 可以设定是否要将需求封锁或是放到队列中,除非有特别设定,ServiceThrottle 属性默认值为 null。
ServiceThrottle 提供三个整数数值的属性设定:
1. MaxConcurrentInstances
这属性表示服务允许并行的服务执行个体的最大数量
2. MaxConcurrentCalls
表示同时间能够处里 operation/Calls 的最大数量,当你执行个体模式是在PerSession或是PerCall都会受此限制,另外PerSession还会受下面MaxConcurrentSessions属性所限制
3. MaxConcurrentSessions
这个属性表示服务端同时间维护的Session的最大个数,Session会随着用户端应用程序终止而结束,但某些用户端如果长时间运行,可能会导致其他用户端遭到封锁
而在传递 Binary 时,使用 MTMO (Message Transmission Mechanism Optimization) 会有较好的性能。
图(三十)、使用 MTMO (Message Transmission Mechanism Optimization)
实践:设定服务节流 (ServiceThrottle)
图(三十一)、新增服务型为项目延伸
图(三十二)、新增 serviceThrottling 项目延伸
图(三十三)、设定 serviceThrottling 项目延伸属性
结语
以上为第一篇 WCF 实战部分,下一篇,笔者将带着大家了解 WCF Routing Services 的世界,了解如何透过 WCF Routing Services 的 Messaging Filter 实践出类似软件 Load Balance 的效果,并使用 Step by Step 方式,带大家实践。
谢谢大家
签名:
学习是一趟奇妙的旅程
这当中,有辛苦、有心酸、也有成果。有时也会有瓶颈。要能够继续勇往直前就必须保有一颗最热诚的心。
软件开发之路(FB 社团):https://www.facebook.com/groups/361804473860062/
Gelis 程序设计训练营(粉丝团):https://www.facebook.com/gelis.dev.learning/
如果文章对您有用,帮我点一下赞,或是点一下‘我要推荐’,这会让我更有动力的为各位读者撰写下一篇文章。
非常谢谢各位的支持与爱护,小弟在此位各位说声谢谢!!! ^_^
原文地址:https://www.cnblogs.com/chinatrump/p/11491041.html