行为(Behaviors)指的是那些影响WCF系统运行的设置。WCF系统中的行为分为服务行为(Service behavior)和操作行为(Operation behavior).常见的服务行为包括实例控制、并发控制、元数据发布。常见的操作行为包括事物流设置。
Public enum InstanceContextMode { PerSession = 0, PerCall = 1, Single =2 }
1.1, PerCall 实例策略:当服务端采用了PerCall 实例策略后,每个客户端请求的消息会被分布到一个新的服务实例上。而一旦这个调用返回之后,服务实例则被销毁。
PerCall调用流程
/// <summary> /// 设置实例管理 /// </summary> [ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall)] public class Service : IService,IDisposable { private int _count = 0; public void Operate() { //由于是PerCall,_count的值不会被保存 _count++; Console.WriteLine("Count的值为{0}",_count); } public void Dispose() { Console.WriteLine("Dispose方法被调用"); } }
1.2, PerSession 实例策略和会话,Persession是默认的实例策略,Persession代表了会话的实例管理模式。需要满足三方面的要求才能在客户端和服务端之间建立会话。
(会话调用流程)
1.2.1 服务契约的会话设置通过ServiceContract的SessionMode属性设置
Public enum SessionMode { Allowed = 0, // 默认设置,允许客户端进行会话通信 Required = 1, // 指服务端要求用会话模式,必须采用传输会话的绑定来进行消息交互,例如//netTcpBinding,NetNamedPipeBinding,服务行为仍然可以采用PerCall模式。 NotAllowed = 2 // 与Required相反 }
[ServiceContract(SessionMode= SessionMode.Allowed] Pulic interface Iservice { [OperationContract] Void Operate(); }
1.2.2 服务行为的实例模式设置
1.2.3 绑定的选择,NetTcpBinding,netNamedPipeBinding使用的协议本身具有传输层会话的能力,而wsHttpBinding,虽然无会话的HTTP协议,可以在头插入会话ID来模仿传输层会话。
using System; using System.ServiceModel; namespace WCF.Fourth { /// <summary> /// 服务契约,定义SessionMode为Allowed /// </summary> [ServiceContract(SessionMode=SessionMode.Allowed)] public interface IService { [OperationContract] void Operate(); } /// <summary> /// 设置实例管理 /// </summary> [ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)] public class Service : IService,IDisposable { private int _count = 0; public void Operate() { //由于是PerSession,_count的值会累加 _count++; Console.WriteLine("Count的值为{0}",_count); } public void Dispose() { Console.WriteLine("Dispose方法被调用"); } } }
1.3 Single实例策略:类似于设计模式的单件模式,所以的客户端代理消息都会发送到同一个服务器的实例上。
using System; using System.ServiceModel; namespace WCF.Fourth { /// <summary> /// 服务契约 /// </summary> [ServiceContract] public interface IService { [OperationContract] void Operate(); } /// <summary> /// 设置实例管理 /// </summary> [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)] public class Service : IService,IDisposable { public int _count = 0; public void Operate() { //由于是Single,_count的值会持续累加 _count++; Console.WriteLine("Count的值为{0}",_count); } public void Dispose() { Console.WriteLine("Dispose方法被调用"); } } }
2.1 并发管理的设置(ConcurrencyMode)是枚举类型
Public enum ConcurrencyMode { Single = 0, //默认 Reetrant = 1, Multiple =2 }
对于PerCall模式,任何一个服务实例都是被单线程调用,不存在并发。而对于PerSession和Single模式,一个服务实例可能被多个线程访问。
2.1.1 Single模式:提供同步锁
using System; using System.ServiceModel; using System.Threading; namespace WCF.Fourth { /// <summary> /// 服务契约 /// </summary> [ServiceContract] public interface IService { [OperationContract] void Operate(); } /// <summary> /// 设置并行管理, /// 为了验证并行管理,这里使用Single实例管理模式 /// </summary> [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single, ConcurrencyMode=ConcurrencyMode.Single)] public class Service : IService,IDisposable { public void Operate() { Console.WriteLine("进入操作"); //延长操作执行时间 Thread.Sleep(1000 * 3); Console.WriteLine("退出操作"); } public void Dispose() { Console.WriteLine("Dispose方法被调用"); } } }
2.1.2 Multiple并发模式。每个操作都允许客户端多个请求同时访问。提高运行效率,防止信息阻塞。
using System; using System.ServiceModel; using System.Threading; namespace WCF.Fourth { /// <summary> /// 服务契约 /// </summary> [ServiceContract] public interface IService { [OperationContract] void Operate(); } /// <summary> /// 设置并行管理, /// 为了验证并行管理,这里使用Single实例管理模式 /// </summary> [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single, ConcurrencyMode=ConcurrencyMode.Multiple)] public class Service : IService,IDisposable { public void Operate() { Console.WriteLine("进入操作"); //延长操作执行时间 Thread.Sleep(1000 * 3); Console.WriteLine("退出操作"); } public void Dispose() { Console.WriteLine("Dispose方法被调用"); } } }
2.1.3 Reetrant 并发模式和Single模式一样,只允许一个线程访问服务操作,在访问进入操作之前必须获得同步锁。不同的是,Reetrant模式解决了Single模式的死锁问题:当服务回调客户端操作时,返回消息将导致死锁。死锁原因:
Reentrant模式解决死锁问题,当服务操作调用其他服务或者回调时,将会释放服务端的同步锁。这样就保证服务的回调消息或者调用链不会发生死锁。
using System; using System.ServiceModel; using System.Threading; namespace WCF.Fourth { /// <summary> /// 服务契约 /// </summary> [ServiceContract(CallbackContract = typeof(ICallback))] public interface IService { [OperationContract] void Operate(); } /// <summary> /// 回调契约 /// </summary> public interface ICallback { [OperationContract] void Callback(); } /// <summary> /// 设置并行管理为Reentrant /// </summary> [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single, ConcurrencyMode=ConcurrencyMode.Reentrant)] public class Service : IService,IDisposable { public void Operate() { Console.WriteLine("{0}进入操作", DateTime.Now.ToString()); //这里进行回调,WCF会释放同步锁 ICallback callback = OperationContext.Current.GetCallbackChannel<ICallback>(); callback.Callback(); Console.WriteLine("{0}退出操作", DateTime.Now.ToString()); } public void Dispose() { Console.WriteLine("Dispose方法被调用"); } } }
3. 元数据的发布:元数据可以视为一个服务的对外接口的描述,服务包含终结点的3要素:地址,绑定,契约
3.1 HTTP—GET方式发布元数据
<behaviors> <serviceBehaviors> <behavior name="MyBehavior"> <serviceMetadata httpGetEnabled = "true"/> </behavior> </behaviors>
using (ServiceHost host = new ServiceHost(typeof(Service))) { //这里添加元数据行为 ServiceMetadataBehavior metadataBehavior = host.Description.Behaviors.Find<ServiceMetadataBehavior>(); if (metadataBehavior == null) { metadataBehavior = new ServiceMetadataBehavior(); metadataBehavior.HttpGetEnabled = true; host.Description.Behaviors.Add(metadataBehavior); } host.Open(); Console.WriteLine("服务已经启动!"); Console.ReadLine(); }
3.2 MEX终结点发布元数据
WCF为MEX终结点提供了基于不同通信协议的专门绑定,如mexTcpBinding、mexNamedPipeBinding、mexHttpBinding
4.1 事物的基本概念和特性
A(原子性-Atomicity)
C (一致性- Consistency)事物必须从一个一致性状态到另一个一致性状态
I (隔离性-Isolation)
D(持续性-Durability)
4.2 单服务事物:整个事物的操作在一个服务中完成
分布式服务:事物的操作涉及多个服务
4.2.1 显示的使用事物类型:比如数据操作时。
4.2.2 使用操作行为(OperationBehavior)声明事物
using System; using System.ServiceModel; using System.Runtime.Serialization; using System.Transactions; namespace WCF.Fourth { /// <summary> /// 服务契约 /// </summary> [ServiceContract] public interface IService { [OperationContract] void SuccessOperation(); [OperationContract] void FailOperation(); [OperationContract] void Assert(); } /// <summary> /// 设置实例管理 /// </summary> [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)] public class Service : IService { private BackAccount A; private BackAccount B; public Service() { Console.WriteLine("服务实例被构造"); A = new BackAccount("A", 100); B = new BackAccount("B", 200); } /// <summary> /// 这里检验两个帐号的金额是否保持一致性 /// </summary> public void Assert() { Console.WriteLine(A); Console.WriteLine(B); Console.WriteLine("A和B帐户的和为{0}", A.Amount + B.Amount); } /// <summary> /// 使用事务 /// </summary> [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)] public void SuccessOperation() { //注册A和B为易失型事务操作 Transaction.Current.EnlistVolatile(A, EnlistmentOptions.None); Transaction.Current.EnlistVolatile(B, EnlistmentOptions.None); A.Add(-50); B.Add(50); } /// <summary> /// 使用事务 /// </summary> [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)] public void FailOperation() { //注册A和B为易失型事务操作 Transaction.Current.EnlistVolatile(A, EnlistmentOptions.None); Transaction.Current.EnlistVolatile(B, EnlistmentOptions.None); A.Add(-50); //这里模拟产生异常 throw new FaultException(); B.Add(50); } } /// <summary> /// 帐号类型,这是一个易失型事务资源 /// </summary> [DataContract] public class BackAccount : IEnlistmentNotification { [DataMember] public String Name; [DataMember] public double Amount; private double _newAmount; public BackAccount(String name, double amount) { Name = name; Amount = amount; } public override string ToString() { return Name + "的账户:" + Amount.ToString(); } public void Adjust(double newAmount) { _newAmount = newAmount; } public void Add(double amount) { double newAmount = Amount + amount; Adjust(newAmount); } /// <summary> /// 提交操作 /// </summary> public void Commit(Enlistment enlistment) { Amount = _newAmount; enlistment.Done(); Console.WriteLine("{0}已提交", Name); } public void InDoubt(Enlistment enlistment) { throw new Exception(); } public void Prepare(PreparingEnlistment enlistment) { enlistment.Prepared(); } /// <summary> /// 回滚操作 /// </summary> public void Rollback(Enlistment enlistment) { enlistment.Done(); Console.WriteLine("{0}已回滚", Name) } } } 4.3 分布式事务:一个事物有多个服务完成
4.3.1 两段提交协议:事务协调器和多个事务组成
4.3.2 事物的流动:事务有途径的从一个服务传到另外一个服务之中。
满足条件:
<binding name="myBinding" transctionFlow="true"></binding> // 绑定事务流动
操作事务流动通过声明TransactionFlow特性来实现。
Public enum TransctionFlowOption { NotAllowed = 0, // 不允许事务流动 Allowed =1, //允许事务流动 Mandatory = 2 // 该操作强制需要事务流动 }
代码见后附件
4.4 事务协议和事务管理器
事务管理器:
代码下载