学习WCF的目的在于使用WCF建立服务,使Sivlerlight程序能够查询和修改Oracle数据的内容,数据库的操作不可避免要涉及数据库事务(Transaction),而基于数据库事务的操作则要求对于某特定客户端程序,开始事务(Transaction Begin)后,事务对象保持不变,才能保证Commit或Rollback操作的成功,为此,查询了相关资料,好像可以通过WCF的服务实例(Service Instance)来控制。
一、基本介绍
尝试了新建一个基本的WCF实例后,开始学习WCF的服务实例,服务实例主要控制WCF客户端与服务端交互时服务端的行为,有三类实例模式:
1:单调服务(Per-Call Service):每次的客户端请求分配一个新的服务实例。
2:会话服务(Sessionful Service):则为每次客户端连接分配一个服务实例
3:单例服务(Singleton Service):所有的客户端会为所有的连接和激活对象共享一个相同的服务实例。类似于Net Remoting的SingleTon模式
二、示例代码
通过一个例子来说明几种服务的区别:
1.契约(CONTRACT)
包括三个函数:SetValue、GetValue、GetSid
[ServiceContract]
public interface IService1
{
[OperationContract]
string SetValue(int value);
[OperationContract]
string GetSid();
[OperationContract]
string GetValue();
// TODO: Add your service operations here
}
服务功能实现(ServiceBehavior)
(1):构造函数:打印当前连接的SessionId
(2):SetValue函数:为类中的intvalue变量赋值
(3):GetValue函数:获取类中的intvalue变量的值
(4):GetSid函数:获取当前连接的SessionId
(5):Dispose函数:显示断开连接的信息,以及该连接的SessionId
public class Service1 : IService1,IDisposable
{
private int intvalue;
private string currentsid;
public Service1()
{
try
{
currentsid = OperationContext.Current.SessionId;
}
catch (Exception ex)
{
Console.WriteLine("get current sid failed,operatincontext.currect is null?" +(OperationContext.Current == null) +" ");
}
Console.WriteLine("Service1 connected:" + currentsid);
}
public string SetValue(int value)
{
intvalue = value;
return string.Format("You entered: {0}", value);
}
public string GetSid()
{
return currentsid;
}
public string GetValue()
{
return intvalue.ToString();
}
#region IDisposable Members
public void Dispose()
{
Console.WriteLine("Service1 disconnected:" + currentsid);
}
#endregion
}
2.寄宿(Host):
ServiceReference1.Service1Client sc1 = new ServiceReference1.Service1Client();
string a;
int tmpInt;
while ((a = Console.ReadLine()) != "exit")
{
if (int.TryParse(a,out tmpInt))
Console.WriteLine(sc1.SetValue(tmpInt));
else if (a == "get")
Console.WriteLine(sc1.GetValue());
else if (a == "sid")
Console.WriteLine(sc1.GetSid());
}
((IDisposable)sc1).Dispose();
Host对应的app.config:
<?xml version="1.0" encoding="utf-8" ?>
- <configuration>
- <system.serviceModel>
<diagnostics performanceCounters="All" />
- <behaviors>
- <serviceBehaviors>
- <behavior name="NewBehavior0">
<serviceMetadata httpGetEnabled="true" httpGetUrl="http://127.0.0.1:8585/is/metadata" />
</behavior>
</serviceBehaviors>
</behaviors>
- <services>
- <service behaviorConfiguration="NewBehavior0" name="WcfService1.Service1">
<endpoint address="" binding="wsDualHttpBinding" bindingConfiguration="" name="ep1" contract="WcfService1.IService1" />
- <host>
- <baseAddresses>
<add baseAddress="http://127.0.0.1:8585/is" />
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
</configuration>
这里使用了wsDualHttpBinding的binging,是因为并不是所有的Binding都支持 Session ,对Per-Call和Singleton而言,binding影响不大。对PerSession,就必须使用特定的Binding, 才可以,否则最终指向的是PerCall,具体的可再进行相关查询
3.客户端(Client)
功能:
当用户在命令行输入一个数字时,则调用SetValue函数,将该数字赋给WCF的intvalue值并打印提示信息,
当用户在命令行中输入get时,调用GetValue函数获取intvalue值并打印出来
当用户在命令行中输入sid时,调用GetSid函数获取当前的SessionId并打印出来
当用户在命令行中输入exit时,断开连接并退出函数
ServiceReference1.Service1Client sc1 = new ServiceReference1.Service1Client();
string a;
int tmpInt;
while ((a = Console.ReadLine()) != "exit")
{
if (int.TryParse(a,out tmpInt))
Console.WriteLine(sc1.SetValue(tmpInt));
else if (a == "get")
Console.WriteLine(sc1.GetValue());
else if (a == "sid")
Console.WriteLine(sc1.GetSid());
}
((IDisposable)sc1).Dispose();
三、三种实例模式的测试
1:persession模式
WCF默认即为该模式,不用对代码进行修改,直接运行即可。
打开多个Client命令行,发现每打开一个命令行,Host的命令行即会打印出一个SessionID
在各Client命令行中,执行setvalue,getvalue,getsid的操作,在Session内部都是一致的,且不与其它Session相关,相关截图如下:
2:percall模式
需要在Service1的类声明前加上一句声明,加完后如下:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class Service1 : IService1,IDisposable
该模式下,每一次任何操作均会打开一个新的Session,但SessionID相同,操作完成后马上关闭该Session,且intvalue的值也不会保存,如果打开多个Client,其SessoinID也相同,截图如下:
3.Single模式
需要在Service1的类声明前加上一句声明,加完后如下:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class Service1 : IService1,IDisposable
该模式下,无论打开多少个Client,服务端只有一个Session,多个Client的intvalue值是共享的(也就是说ClientA将该值设为123,那ClientB获取的值就是123)
此外,在这个模式下,没有SessionID的概念,在尝试获取这个ID时,会返回空值,截图如下: