1 设计说明
Redis是现在比较流行的NoSQL,本示例仿照Redis,实现了一些类似的功能。对本示例稍加扩展和修改就可实现诸如队列服务的应用。
2 技术要点
2.1 服务契约
操作重载
不支持操作重载,所有方法必须具有唯一名称。
指定别名
用OperationContractAttribute的Name属性指定别名。对于被指定别名的两个方法名可以相同,但别名不能相同。另外注意,代理中的方法亦使用别名。
契约继承
服务契约接口支持继承功能,但接口层级中的每个接口都要使用ServiceContractAttribute标记。
客户端契约继承
服务端多个接口组成一个契约层级结构,但客户端代理类中可以取消层级关系,但也可保留层级关系。
2.2 数据契约
虽然WCF可以推断数据契约,但不推荐这样使用,应将DataContractAttribute和DataMemberAttribute应用到类型和属性上。
可托管WCF的Windows进程(宿主)为:控制台应用程序,Windows Form应用程序,WPF应用程序,Windows Service应用程序,IIS 5/6(不稳定,不建议采用),WAS(建议采用)。
采用WAS托管而分自托管的好处是省去一些编码和测试工作,而且如果采用BasicHttpBinding那么使用自托管倒不如使用WAS托管来的方便。唯一不足的是无法对服务进行一些个性化的控制。
特别提及的是,IIS 7默认采用WAS托管网站,所以默认情况下使用的是IIS托管程序,其实使用的是WAS。
采用控制台应用程序,Windows Form应用程序,WPF应用程序,Windows Service应用程序托管,称为自托管方式。
2.1.1自托管
自托管应用ServcieHost类,使用Open()方法允许调用传入,使用Close()方法终结宿主实例。当调用Close()方法后,即使宿主进程还在运行,也会拒绝调用传入。
对宿主实例正确的管理方式:
ServiceHost host = new ServiceHost(typeof(IService)); try { //若打开时发生异常,那么后面无法正常关闭,因此要使用Abort方法 host.Open(); //根据情况决定是否关闭 host.Close(); } catch (CommunicationException cex) { host.Abort(); //记录异常...... } catch (TimeoutException tex) { host.Abort(); //记录异常...... } catch (Exception ex) { host.Abort(); //记录异常...... }
2.1.2设置关闭超时值
调用ServiceHost 的属性CloseTimeOut进行设置,若Close方法没有在超时时间内关闭宿主实例时,当超时时间到达时关闭宿主实例。
2.3 绑定
2.4 客户端编程
2.4.1代理
使用命令行工具SvcUtil.exe生成代理类。可是有out指定代理文件名称。一般将生成的代理稍加修改后使用。
例:
SvcUtil.exe http://localhost:8000/MyService/out:Proxy.cs
2.4.2 关闭代理
代理类派生自ClientBase类,T为契约类型。
关闭代理的结果:
l 释放代理与服务的链接。
l 终止服务实例的会话。
关闭代理的重要性:
确保客户端最大链接数不会达到阈值。
使用Using语句关闭代理:
不显式调用Close方法,而是使用Using语句关闭代理,使代码更简洁,缺点是不便于异常处理。
使用Close方法关闭代理:
当客户端调用方法抛出异常时,无法使用Close()方法关闭代理,此时应使用Abort()方法。
ServiceProxy proxy = new ServiceProxy(); try { proxy.Function(); proxy.Close(); } catch { proxy.Abort(); }
2.4.3调用超时
客户端调用必须在配置时间内完成,否则客户端会收到TimeoutException。默认的超时值为1min。
通过绑定类型的SendTimeout属性可设置超时值,继承了基类Binding的类型,都可通过SendTimeout属性配置。
通过配置文件也可配置:
......
2.5 服务行为
WCF服务行为是服务本地的特性,包括两种:
配置服务的行为ServiceBehaviorAttribute,影响契约与操作。用于配置实例化方式。
配置操作的行为OperationBehaviorAttribute。用于配置操作方式。
2.6 实例化
WCF支持三种实例化方式:单调模式,会话模式,单例模式。通过InstanceContextMode可配置实例化模式,默认模式为会话模式。
2.6.1 单调模式
为每次的客户端调用分配一个新实例,具体过程如下:
1)客户端调用代理,代理将调用转发给服务。
2)服务创建一个实例,然后调用服务实例的方法。
3)实例方法调用返回时,如果服务实现了IDisposable接口,服务调用IDisposable.Dispose()方法,接着服务上下文被销毁。
在上述过程中只要不调用代理的Close()或Abort()方法,服务与客户端的链接就不会断开。
配置单调服务
对服务类型使用ServiceBehaviorAttribute特性,将ServiceBehaviorAttribute的属性InstanceContextMode设置为InstanceContextMode.PerCall
2.6.2 会话模式
为每次客户端连接分配一个服务实例,一个客户端的所有调用共享一个服务实例。客户端关闭代理时会终止会话。同时若服务实现了IDisposable接口,客户端会异步调用IDisposable.Dispose()方法。
配置会话服务
对服务类型使用ServiceBehaviorAttribute特性,将ServiceBehaviorAttribute的属性InstanceContextMode设置为InstanceContextMode.PerSession
SessionMode
SessionMode的设置会影响服务是否支持会话模式,且与InstanceContextMode一起使用。SessionMode是枚举类型的,成员包括Allowed,NotAllowed,Required。SessionMode默认值为Allowed,指定当绑定支持会话时,协定也支持会话。NotAllowed协定永不支持启动会话,Required协定需要会话绑定。 如果绑定并未配置为支持会话,则将引发异常。
组合配置情形
服务实例化模式与绑定、契约的会话模式(SessionMode),服务的实例上下文模式(InstanceContextMode)的配置有关,具体组合形式见下表
2.6.3 单例模式
所有的客户端共享一个相同的服务实例。
配置单例模式
对服务类型使用ServiceBehaviorAttribute特性,将ServiceBehaviorAttribute的属性InstanceContextMode设置为InstanceContextMode.Single
2.7 操作
操作类型包括三种:请求应答操作,单向操作,回调操作,其中请求应答操作是默认的操作模式。
2.7.1请求应答操作
请求应答操作中,如果不采用异步操作,那么客户端发出请求,阻塞客户端直到调用返回。
默认超时值
默认的应答超时值为1min,等待返回值超过1min时,客户端获得TimeoutException异常。
支持的绑定
除NeetPeerTcpBinding和NetMsmBinding外,都支持此操作。
2.7.2单向操作
无返回值,属于即发即弃的调用方式,服务端抛出的异常不能传递到客户端。
不等同于并发调用
单向调用到达服务端时不会立即分发执行,而是被放入服务端队列,并在某个合适的时间分发执行。如果服务端队列已满,那么单向调用会阻塞客户端直到调用被放入队列中。队列的容量与配置的通道和可靠性模式有关。
配置单向调用
将OperationContract的IsOneWay设置为true即为单向调用。
2.7.3 回调操作
2.8 限流
开发者限制客户端的链接数和服务端的负荷。如果超过了限流设置,WCF将调用放入队列中,逐个进行处理,若客户端等待的时间超过预设的超时阈值,那么客户端会获得TimeoutException异常。
设置限流参数
1)并发会话最大数
服务支持的独立客户端的最大数目,默认为处理器内核数的100倍。对于像基本绑定这样不支持传输会话的类型而言,该设置无效。
2)并发调用最大数
所有服务实例当前正在执行的调用总数。默认值为处理器内核数的16倍。
3)并发实例最大数
并发实例上下文总数。默认为最大并发会话数与最大并发调用数之和。
配置限流
配置限流参数
以编程的方式设置限流参数
ServiceHost host = new ServiceHost(typeof(Service1)); ServiceThrottlingBehavior stb = host.Description.Behaviors.Find(); //实例化ServiceThrottlingBehavior,设置限流参数 ServiceThrottlingBehavior stbNew = new ServiceThrottlingBehavior(); stbNew.MaxConcurrentCalls = 200; stbNew.MaxConcurrentInstances = 100; stbNew.MaxConcurrentSessions = 300; //检查是否已配置限流 if (stb != null) { //存在则删除原有配置 host.Description.Behaviors.Remove(stbNew); } host.Description.Behaviors.Add(stbNew); host.Open();
当打开宿主后,不可修改限流参数,只可查询,否则抛出异常InvalidOperationException。
查看限流参数
ChannelDispatcher cd = OperationContext.Current.Host.ChannelDispatchers[0] as ChannelDispatcher;ServiceThrottle st = cd.ServiceThrottle;
2.9 并发管理
并发模式
通过设置ServiceBehaviorAttribute的ConcurrencyMode属性来控制服务的并发模式:
1)ConcurrencyMode.Single:同步访问模式。默认的并发访问模式。
2)ConcurrencyMode.Multiple:并发访问模式。对于此模式下的同步问题,可以锁住服务实现的整个方法,使用MethodImplAttribute的构造函数MethodImplAttribute(MethodImplOptions methodImplOptions),向其传递MethodImplOptions.Synchronized,可以实现同步。
并发调用与实例化模式
三种实例化模式默认的并发模式均为ConcurrencyMode.Single。
2.10 传输会话
传输会话确保来自一个客户端的消息被发送到宿主同一个传输通道上,传输会话是WCF的基础概念,它影响可靠性、实例管理、错误管理、同步、事物和安全。传输会话使得WCF具有识别客户端的能力。
2.10.1传输会话终止
客户端关闭代理能够终止传输会话。传输会话具有空闲超时值,默认是10min。当客户端处于非活动状态超过10min的时候,传输会话就会终止。若此时客户端仍使用代理,那么客户端会收到CommunicationObjectFaultedException异常。
2.10.2设置传输会话超时值
配置超时值
编程设置超时值
NetTcpBinding ntb = new NetTcpBinding();ntb.ReliableSession.InactivityTimeout = TimeSpan.FromMinutes(10);