现在的位置: 首页 > 综合 > 正文

Step by Step WCF—Instance Management

2012年01月04日 ⁄ 综合 ⁄ 共 2997字 ⁄ 字号 评论关闭

在本次实验中你将会体会到三种不同的实例管理模式。打开Instance Management文件夹下的InstanceManagement.sln解决方案。解决方案中包含了一个简单的服务器端和客户端。它们都被配置为了BasicHttpBinding。

<services>
 
<service name = "MyNamespace.MyService">
 
<endpoint
    
address  = "http://localhost:8000/MyService"
 
    binding  
= "basicHttpBinding"

    contract 
= "MyNamespace.IMyContract" 
 
/>

 
</service>

为了监视实例的创建、回收和状态,service端的代码在它的三个方法:构造函数、MyMethod()和Dispose()中都会显示一个MessageBox来表明状态。另外service中有一个m_Counter的int型字段,我们可以通过观察它来得知我们是不是获得了一个新的实例。

[ServiceContract]
interface
 IMyContract
{
  [OperationContract]
  
void
 MyMethod();
}

class MyService : IMyContract,IDisposable
{
  
int m_Counter = 0
;
  
public
 MyService()
  
{
  MessageBox.Show(
"Counter = " + m_Counter,"MyService.MyService()"
);
  }

  
public void MyMethod()
  
{
  m_Counter
++
;
  MessageBox.Show(
"Counter = " + m_Counter,"MyService.MyMethod()"
);

  
string sessionID =
 OperationContext.Current.SessionId;
  Trace.WriteLine(
"Service Session ID: " + (sessionID??"None"
));
  }

  
public void Dispose()
  
{
  MessageBox.Show(
"","MyService.Dispose()"
);
  }

}


MyMethod方法同样还记录了session ID。

Client端的代码创建了一个代理来调用MyMethod()方法:

void OnCall(object sender,EventArgs e)
{
 MyContractClient proxy 
= new
 MyContractClient();

 proxy.MyMethod();
 proxy.MyMethod();

 IContextChannel channel 
=
 proxy.InnerChannel;
 
string sessionID =
 channel.SessionId;
 Trace.WriteLine(
"Client Session ID: " + (sessionID??"None"
));

 proxy.Close();
}

Client端同样记录了session ID。编译并运行程序。

Per-Call模式
Per-Call意味着对于两次client端的调用,你将会得到两个不同的实例。也就是说即使client端两次调用使用的是相同的代理,每一次调用服务器端实例构造函数都会被调用一次。m_Counter的值始终都是1。在函数返回后Dispose()方法都会在后台被执行。注意到,在Debug窗口中我们可以观察到session ID都是没有的。
我们也可以显示的将服务配置为Per-Call类型。只需要将InstanceContextMode属性设置为InstanceContextMode.PerCall即可:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
class
 MyService : IMyContract, IDisposable
{……}

Per-Session模式
接下来,我们将会把服务配置为每个客户端都会关联到一个特定的服务,类似于经典的C/S模式。将服务器属性InstanceContextMode修改为InstanceContextMode.PerSession:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
class
 MyService : IMyContract, IDisposable
{……}

你会看到,服务仍然是Per-Call的,并没有session。因为要将session设置为contract的一部分,这样才会有效果。打开MyService.cs文件,将service contract的SessionMode属性设置为

SessionMode.Required:
[ServiceContract(SessionMode 
=
 SessionMode.Required)]
interface
 IMyContract
{……}

同样,在client端的Proxy.cs文件中也需要做这样的定义。
编译程序并运行,你会得到如下的异常:
 
这是因为BasicHttpBinding不支持session。打开app.config文件,将binding改为WSHttpBinding:

 <service name = "MyNamespace.MyService">
    
<endpoint
       address  
= "http://localhost:8000/MyService"
 
       binding  
= "wsHttpBinding"

       contract 
= "MyNamespace.IMyContract" 
    
/>

 
</service>

在client端也做同样的设置。
编译后运行程序。这一次你将只会得到一个服务器实例,counter的数量会变为2,实例也仅仅是在client端关闭后调用一次。启动两个client程序观察一下呢?

单实例模式
第三种是单实例模式(Singleton),即所有client端都连接到同一个实例上。将服务器属性InstanceContextMode修改为InstanceContextMode.Single:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
class
 MyService : IMyContract, IDisposable
{……}

编译并运行程序,你将会看到,在没有任何client调用的时候服务器端的构造函数已经执行了。点击client端的button两次,counter的数量应该为4。关闭client程序,Dispose方法仍然没有被调用。
单实例模式是不需要session的,将SessionMode=SessionMode.Required去掉再试试看呢。

抱歉!评论已关闭.