HTML5技术

快速入门系列--WCF--01基础概念 - 熊二哥(4)

字号+ 作者:熊二哥 来源:博客园 2016-02-25 19:53 我要评论( )

从基础架构的角度上看,WCF可以分为服务模型层和信道层两个层次,服务模型层建立在信道层的基础是上,而信道层就是通过本节即将介绍的binding绑定创建,注意这儿的绑定与.NET很多地方的绑定概念不同(例如最常见的

从基础架构的角度上看,WCF可以分为服务模型层和信道层两个层次,服务模型层建立在信道层的基础是上,而信道层就是通过本节即将介绍的binding绑定创建,注意这儿的绑定与.NET很多地方的绑定概念不同(例如最常见的数据绑定),注意理解。那么binding是如何创建信道层的呢?它通过组合不同的信道,将其整合为一个指定的信道栈,这个过程其实就是一个职责链模式的实现,每个信道都只处理自己的一部分内容,最基本的有传输、编码,复杂一些的包括事务流转、安全传输和可靠传输,使得整个框架足够灵活,已于扩展,一个支持WS-*的信道栈如下图所示。

其中传输信道实现了基于某种协议的消息传输,消息编码信道实现了消息的编码(例如XML、Binary、MTOM),而WS-AT(WS-Atomic Transaction)实现了分布式的事务支持,WS-RM(WS-Reliable Messaging)实现了信息的可靠传输,WS-Security实现了消息的传输安全,他们都可以被称为协议信道。接下来通过一个简单的例子来演示通过绑定进行消息通信,在其中将引入信道、信道监听器、信道工厂等主要对象。

 View Code

通过这个例子看起来很像以前的Window网络编程中的Socket编程形式,首先服务端监听,然后客户端请求,服务端接收并绑定Socket(这儿是绑定信道),之后就可以在此基础上进行通讯了。这部分涉及到的类型很多,接下来通过一个表格简述部分主要类,浏览即可。

类别

介绍

信道与信道栈

最基础的ICommunicationObject接口,提供统一管理通信对象的状态机,可以作为一种设计范例用于实际项目中;DefaultCommunicationTimeouts类负责控制超时时限;IChannel和ChannelBase用于表示信道;ISession和ISessionChannel<TSession>用于表示会话信道。此外,支持3种消息交换模式。

数据报Datagram模式:一般使一部的消息发送方式,支持1或多个接收者,对应IOutputChannel, IInputChannel

请求-回复模式:对应IRequestChannel、IReplyChannel

双工模式:对应IDuplexChannel

信道监听器(Server)

IChannelListener, ChannelListenerBase

信道工厂(Client)

IChannelFactory, ChannelFactoryBase

最后,进入绑定元素与绑定的介绍,之前提到过,绑定是用于创建信道栈的,而它其中的绑定元素则是用于创建具体的信道的。常见的系统绑定包括:BasicHttpBinding、WSHttpBinding、WS2007HttpBinding、WSDualHttpBinding、NetTcpBinding、NetNamedPipeBinding和NetMsmqBinding。其中BasicHttpBinding最为基础,在构建类似web服务形式的应用中使用最多,所有带Net前缀的绑定将局限于.NET平台,不同的绑定的运行效率有不小差异。一般来说,企业内部的服务推荐使用RPC类型的服务,如NetTcpBinding,而对外服务推荐使用WSHttpBinding,当然实际项目中,对外服务一般不会使用WCF框架,而是使用Restful风格的WebAPI。此外,也可以建立自定义的绑定,将框架提供的绑定元素进行重新组合,更有甚者,可以自定义绑定元素,不过这部分内容使用的场景非常的少。最后,提供一个简单自定义绑定配置作为参考,其组合了传输、编码和安全3个绑定元素,前两者是必选项,且必须按照顺序构建。

复制代码
1 <bindings >
2 <customBinding>
3 <binding name="testBinding">
4 <security></security>
5 <textMessageEncoding></textMessageEncoding>
6 <tcpTransport></tcpTransport>
7 </binding>
8 </customBinding>
9 </bindings>
复制代码

 

契约其实就是一个生活中的概念,是一种双边和多边的协议,在WCF中,其保证了无论服务的实现有任何的改变,而服务的消费者始终可以通过契约约定方式来调用服务。由于整个WCF都是基于SOAP以及WS-*的,因此其XML是数据格式标准,通过XSD控制XML的数据结构,用WSDL(web服务描述语言)来提供跨平台的描述服务。

服务契约的定义通过ServiceContractAttribute和OperationContractAttribute两个特性来定义,前者定义整个服务,后者定义服务中具体的方法,接下来具体介绍一下这两个类。ServiceContractAttribute类,比较重要的属性包括:Name,可以定义服务的名称,默认为接口名;Namespace定义服务的命名空间,可以使用自己的公司名和项目名的组合来设定,其和之前的Name在wsdl文件中均是对<portType>元素的修饰;ConfigurationName实际上就对应配置中的Contract名称;SessionMode表示契约的会话模式,比如Allowed、Required等;ProtectionLevel表示消息的保护级别;CallbackContract在双工通信时指定回调操作的接口类型。OperationContractAttribute类,其属性Name、Namespace、ProtectionLevel与之前相似,值得一提的属性包括:Action/ReplyAction用于控制某个操作请求/回复信息的<Action>头,其默认通过命名空间、服务契约、操作名称组成,后者默认添加Response;IsOneWay控制消息交换的模式。提到消息交换的模式,记得之前提到过主要的三种请求-回复、单向和双工,前两项之前的例子中已有展示,之后的示例将展示双工模式。

复制代码
 1 服务端:
 2 public interface IAddCallback
 3 {
 4 [OperationContract]
 5 void DisplayResult(CompositeType result, CompositeType a, CompositeType b);
 6 }
 7 [ServiceContract(CallbackContract=typeof(IAddCallback))]
 8 public interface IAddService
 9 {
10 [OperationContract]
11 void Add(CompositeType a, CompositeType b);
12 }
13  
14 [DataContract]
15 public class CompositeType
16 {
17 [DataMember]
18 public int PartA { get; set; }
19 [DataMember]
20 public string PartB { get; set; }
21 }
22 public class AddCallbackService : IAddCallback
23 {
24 public void DisplayResult(CompositeType result, CompositeType a, CompositeType b)
25 {
26 Console.WriteLine("x + y = {2} when x= {0} and y = {1}", a.PartA, b.PartA, result.PartA);
27 }
28 }
29 
30 public class AddService : IAddService
31 {
32 public void Add(CompositeType a, CompositeType b)
33 {
34 var result = new CompositeType() { PartA = a.PartA + b.PartA, PartB = a.PartB + b.PartB };
35 IAddCallback callback = OperationContext.Current.GetCallbackChannel<IAddCallback>();
36 callback.DisplayResult(result, a, b);
37 }
38 }
39 
40 配置:
41 <system.serviceModel>
42 <behaviors>
43 <serviceBehaviors>
44 <behavior name="metadataBehavior">
45 <serviceMetadata httpGetEnabled="True" httpGetUrl="http://127.0.0.1:9901/addservice/metadata"/> 
46 <serviceDebug includeExceptionDetailInFaults="true"/>
47 </behavior>
48 </serviceBehaviors>
49 </behaviors>
50 <services>
51 <service name="Sory.Entertainment.WCF.AddService" behaviorConfiguration="metadataBehavior">
52 <endpoint address="net.tcp://127.0.0.1:1001/addservice" binding="netTcpBinding" contract="Sory.Entertainment.WCF.IAddService"/>
53 </service>
54 </services>
55 </system.serviceModel>
56 
57 客户端:
58 
59 InstanceContext callback = new InstanceContext(new AddCallbackService());
60 using (DuplexChannelFactory<IAddService> channelFactory = new DuplexChannelFactory<IAddService>(callback, "addservice"))
61 {
62 var addChannel = channelFactory.CreateChannel();
63 addChannel.Add(new CompositeType { PartA = 1 }, new CompositeType { PartA = 2 });
64 }
65 
66 配置:
67 <system.serviceModel>
68 <client>
69 <endpoint name="addservice" address="net.tcp://127.0.0.1:1001/addservice" binding="netTcpBinding" contract="Sory.Entertainment.WCF.IAddService"/>
70 </client>
71 </system.serviceModel>
复制代码

当调用以上示例的服务时,会抛出一个关于死锁的异常,原因是其在并发场景下会造成回调死锁的情况,可以通过将请求或回调方法设置为单向即可。

此外,服务契约是不支持继承的,而操作契约支持继承,不过这部分也不太常用,而与契约相关的元数据描述类也非常简单,这儿就不展开介绍了。

  • 多线程和异步操作

在《CLR via C#》中,将操作分为计算限制的和I/O限制的,一般来说,WCF中主要涉及到I/O限制的操作,这种类型的操作主要是通过异步模型来提高其并发性。谈到异步操作,在SOA这类应用中包含3个不同异步场景,这部分知识比较有意思,曾经困到鄙人多年。这3中场景包括:异步的信道调用,客户端可以通过代理对象异步的调用信道;单向消息交换,客户端的信道通过单向的消息交换模式向服务端发送消息,发送立刻返回;异步服务实现,服务端在具体实现服务操作时,采用异步调用的方式。

异步服务代理的创建,可以通过在添加服务引用时通过高级选项添加生成异步操作选项,之后可以通过使用BeginXX/EndXX方法、回调和事件注册等方式使用异步服务代理类。而异步的服务实现可以在服务接口中将原有方法修改为BeginXXX/EndXXX形式的异步方法名,并将OperationContract契约的AsyncPattern属性设置为true即可。

  • 操作的选择与执行

之前提及的契约描述类中的Operations列表只包含了被OperationContractAttribute特性修饰的服务操作,而运行时的操作是通过DispatchOperation和ClientOperation两个类型表示。DispatchOperation在服务端的终结点分发器初始化时建立一个DispatchRuntime类,其通过一个SynchronizedKeyedCollection<string, DispatchOperation>集合类型来管理所有的运行时分发操作,OperationSelector用于操作选择,IOperationInvoker用于操作执行。ClientOperation和前者的结构基本一致,只不过它用于客户端而已。

 

 

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

相关文章
  • 如何快速处理线上故障 - 倒骑的驴

    如何快速处理线上故障 - 倒骑的驴

    2017-05-02 12:01

  • HTML5 进阶系列:拖放 API 实现拖放排序 - _林鑫

    HTML5 进阶系列:拖放 API 实现拖放排序 - _林鑫

    2017-05-02 11:02

  • 【Vue 入门】使用 Vue2 开发一个展示项目列表的应用 - zhangjk

    【Vue 入门】使用 Vue2 开发一个展示项目列表的应用 - zhangjk

    2017-04-30 16:00

  • JS组件系列——自己动手封装bootstrap-treegrid组件 - 懒得安分

    JS组件系列——自己动手封装bootstrap-treegrid组件 - 懒得安分

    2017-04-28 14:02

网友点评