理解 WCF 中的实例管理





5.00/5 (1投票)
理解 WCF 中的实例管理
实例管理是 WCF 用来将客户端请求绑定到服务实例的技术,它决定了哪个服务实例处理哪个客户端请求,以及何时处理。WCF 支持 3 种实例激活模式。
- 按调用:为每个客户端请求分配和销毁一个新的服务实例。
- 按会话:为每个客户端连接分配一个服务实例。
- 单例:所有客户端、所有连接和所有激活共享同一个服务实例。
总的来说,服务实例模式严格来说是一个服务器端实现细节,不应该以任何方式在客户端体现。
现在,让我们定义一个演示实际实例管理的服务的。
创建类库
让我们创建一个服务,创建一个新项目,选择“类库”模板,将其命名为InstanceLib
,然后对新创建的项目进行一些整理。
- 从项目中删除文件 Class1.cs。
- 向项目中添加一个名为
ISingleCallService
的新**接口**,将向项目中添加一个新文件ISingleCallService.cs。 - 向项目中添加一个名为
SingleCallService
的新**类**,它将实现ISingleCallService
接口,将向项目中添加一个新文件SingleCallService.cs。 - 向项目中添加一个名为
ISessionService
的新**接口**,将向项目中添加一个新文件ISessionService.cs。 - 向项目中添加一个名为
SessionService
的新**类**,它将实现ISessionService
** 接口,将向项目中添加一个新文件SessionService.cs。<!--EndFragment--> - 向项目中添加一个名为
ISingletonService
的新接口,将向项目中添加一个新文件ISingletonService.cs。 - 向项目中添加一个名为
SingletonService
的新类,它将实现ISingletonService
** 接口,将向项目中添加一个新文件SingletonService.cs。
为了简单起见,我们假设每个接口只定义一个方法,该方法仅将传入的值添加到其成员变量中。
定义接口
所以,让我们为每个服务定义接口。
// Listing of ISingleCallService.cs
using System;
using System.Text;
using System.ServiceModel;
namespace InstanceLib
{
[ServiceContract]
interface ISingleCallService
{
[OperationContract]
double AddValue (double dblNum);
}
}
// Listing of ISessionService.cs
using System;
using System.Text;
using System.ServiceModel;
namespace InstanceLib
{
[ServiceContract]
interface ISessionService
{
[OperationContract]
double AddValue (double dblNum);
}
}
// Listing of ISingletonService.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
namespace InstanceLib
{
[ServiceContract]
interface ISingletonService
{
[OperationContract]
double AddValue (double dblNum);
}
}
- <!--EndFragment--><!--EndFragment-->
实现接口
让我们实现每个接口,如下所示
// Listing of SingleCallService.cs
using System;
using System.Text;
using System.ServiceModel ;
namespace InstanceLib
{
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall)]
public class SingleCallService : ISingleCallService
{
private double m_dblTotal = 0 ;
public double AddValue(double dblVal)
{
m_dblTotal += dblVal;
return m_dblTotal;
}
}
}
重要
您可以注意到类的 ServiceBehavior
属性,该属性被定义为 InstanceContextMode.PerCall
,它指定在每次调用之前创建一个新的 InstanceContext
对象,并在调用之后回收。如果省略此属性或未指定,则默认假定为 InstanceContextMode.PerCall
。
// Listing of SessionService.cs
using System;
using System.Text;
using System.ServiceModel;
namespace InstanceLib
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class SessionService : ISessionService
{
private double m_dblTotal = 0 ;
public double AddValue(double dblVal)
{
m_dblTotal += dblVal;
return m_dblTotal;
}
}
}
重要
您可以注意到类的 ServiceBehavior
属性,该属性被定义为 InstanceContextMode.PerSession
,**它指定为每个会话创建一个 InstanceContext
对象。
// Listing of SingletonService.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
namespace InstanceLib
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class SingletonService : ISingletonService
{
private double m_dblTotal = 0 ;
public double AddValue(double dblVal)
{
m_dblTotal += dblVal;
return m_dblTotal;
}
}
}
重要
您可以注意到类的 ServiceBehavior
属性,该属性被定义为 InstanceContextMode.Singlel
,它指定所有传入的调用都使用一个 InstanceContext
对象,并且不会被回收。如果服务对象不存在,则会创建一个。
如果您注意到所有 3 个服务实现,您将注意到每个类在 ServiceBehavior
类属性上的区别,除此之外,所有实现的接口都具有相同的实现。它们只是将传入的值添加到类的成员变量中。
生成项目,您的类库就准备好了。
托管服务
为了简单起见,我将此服务作为自托管服务进行托管,要创建宿主应用程序,请创建一个新的**基于控制台的应用程序**。
在编写宿主应用程序的任何代码之前,让我们定义服务(们)的配置文件。
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<services>
<!–************************ Single Call Service ************************ –>
<service name="InstanceLib.SingleCallService"
behaviorConfiguration="SingleCallServiceBehavior">
<host>
<baseAddresses>
<add baseAddress="https://:9011/SingleCallService"/>
<add baseAddress="net.tcp://:9012/SingleCallService"/>
</baseAddresses>
</host>
<endpoint address="https://:9011/SingleCallService"
binding="wsHttpBinding" contract="InstanceLib.ISingleCallService"/>
<endpoint address="net.tcp://:9012/SingleCallService"
binding="netTcpBinding" contract="InstanceLib.ISingleCallService"/>
<endpoint address="mex" binding="mexHttpBinding"
contract="IMetadataExchange"/>
<endpoint address="mex" binding="mexTcpBinding"
contract="IMetadataExchange"/>
</service>
<!—************************ Single Session Service ************************–>
<service name="InstanceLib.SessionService"
behaviorConfiguration="SessionServiceBehavior">
<host>
<baseAddresses>
<add baseAddress="https://:9013/SessionService"/>
<add baseAddress="net.tcp://:9014/SessionService"/>
</baseAddresses>
</host>
<endpoint address="https://:9013/SessionService"
binding="wsHttpBinding" contract="InstanceLib.ISessionService"/>
<endpoint address="net.tcp://:9014/SessionService"
binding="netTcpBinding" contract="InstanceLib.ISessionService"/>
<endpoint address="mex" binding="mexHttpBinding"
contract="IMetadataExchange"/>
<endpoint address="mex" binding="mexTcpBinding"
contract="IMetadataExchange"/>
</service>
<!—************************** Singleton Service **************************–>
<service name="InstanceLib.SingletonService"
behaviorConfiguration="SingletonServiceBehavior">
<host>
<baseAddresses>
<add baseAddress="https://:9015/SingletonService"/>
<add baseAddress="net.tcp://:9016/SingletonService"/>
</baseAddresses>
</host>
<endpoint address="https://:9015/SingletonService"
binding="wsHttpBinding" contract="InstanceLib.ISingletonService"/>
<endpoint address="net.tcp://:9016/SingletonService"
binding="netTcpBinding" contract="InstanceLib.ISingletonService"/>
<endpoint address="mex" binding="mexHttpBinding"
contract="IMetadataExchange"/>
<endpoint address="mex" binding="mexTcpBinding"
contract="IMetadataExchange"/>
</service>
</services>
<!– **************************** behaviors ************************** –>
<behaviors>
<serviceBehaviors>
<!– Single Call Service Behavior –>
<behavior name="SingleCallServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
</behavior>
<!–Single Session Service Behavior –>
<behavior name="SessionServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
</behavior>
<!–Singleton Service Behavior –>
<behavior name="SingletonServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
现在让我们分析配置文件。
按调用服务
<!–******************* Single Call Service ************************** –>
<service name="InstanceLib.SingleCallService"
behaviorConfiguration="SingleCallServiceBehavior">
<host>
<baseAddresses>
<add baseAddress="https://:9011/SingleCallService"/>
<add baseAddress="net.tcp://:9012/SingleCallService"/>
</baseAddresses>
</host>
<endpoint address="https://:9011/SingleCallService"
binding="wsHttpBinding" contract="InstanceLib.ISingleCallService"/>
<endpoint address="net.tcp://:9012/SingleCallService"
binding="netTcpBinding" contract="InstanceLib.ISingleCallService"/>
<endpoint address="mex"
binding="mexHttpBinding" contract="IMetadataExchange"/>
<endpoint address="mex"
binding="mexTcpBinding" contract="IMetadataExchange"/>
</service>
会话服务
<!—************************* Single Session Service ************************* –> <service name="InstanceLib.SessionService" behaviorConfiguration="SessionServiceBehavior"> <host> <baseAddresses> <add baseAddress="https://:9013/SessionService"/> <add baseAddress="net.tcp://:9014/SessionService"/> </baseAddresses> </host> <endpoint address="https://:9013/SessionService" binding="wsHttpBinding" contract="InstanceLib.ISessionService"/> <endpoint address="net.tcp://:9014/SessionService" binding="netTcpBinding" contract="InstanceLib.ISessionService"/> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/> <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange"/> </service>
单例服务
<!—************************** Singleton Service **************************–> <service name="InstanceLib.SingletonService" behaviorConfiguration="SingletonServiceBehavior"> <host> <baseAddresses> <add baseAddress="https://:9015/SingletonService"/> <add baseAddress="net.tcp://:9016/SingletonService"/> </baseAddresses> </host> <endpoint address="https://:9015/SingletonService" binding="wsHttpBinding" contract="InstanceLib.ISingletonService"/> <endpoint address="net.tcp://:9016/SingletonService" binding="netTcpBinding" contract="InstanceLib.ISingletonService"/> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/> <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange"/> </service>
编写宿主服务的代码
// Listing of Program.cs
using System;
using System.Text;
using System.ServiceModel;
namespace InstanceLibHost
{
class Program
{
static void Main(string[] args)
{
ServiceHost m_SingleCallHost = null;
ServiceHost m_SingleSessHost = null;
ServiceHost m_SingletonHost = null;
Console.WriteLine("\nHosting Single Call Service at >> " );
Console.WriteLine(" https://:9011/SingleCallService");
Console.WriteLine(" net.tcp://:9012/SingleCallService");
try
{
m_SingleCallHost = new ServiceHost(typeof(InstanceLib.SingleCallService));
m_SingleCallHost.Open();
}
catch (Exception eX)
{
Console.WriteLine("Failed while starting
Single Call Service Service [" + eX.Message + "]");
m_SingleCallHost = null;
}
if ( m_SingleCallHost!= null )
Console.WriteLine("Single Call Service hosted successfully . . .");
Console.WriteLine("\nHosting Single Session Service at >> ");
Console.WriteLine(" https://:9013/SessionService");
Console.WriteLine(" net.tcp://:9014/SessionService");
try
{
m_SingleSessHost = new ServiceHost(typeof(InstanceLib.SessionService));
m_SingleSessHost.Open();
}
catch (Exception eX)
{
Console.WriteLine("Failed while starting Single
Session Service [" + eX.Message + "]");
m_SingleSessHost = null;
}
if (m_SingleSessHost != null) Console.WriteLine
("Single Session Service hosted successfully . . .");
Console.WriteLine("\nHosting Singlton Service at >> " );
Console.WriteLine(" https://:9015/SingletonService" );
Console.WriteLine(" net.tcp://:9016/SingletonService");
try
{
m_SingletonHost = new ServiceHost(new InstanceLib.SingletonService());
m_SingletonHost.Open();
}
catch (Exception eX)
{
Console.WriteLine("Failed while starting Service [" + eX.Message + "]");
m_SingletonHost = null;
}
if (m_SingletonHost != null) Console.WriteLine("Singleton Service hosted successfully . . .");
Console.WriteLine("Press any key to close . . ." );
Console.ReadKey();
m_SingleCallHost.Close ();
m_SingleSessHost.Close ();
m_SingletonHost.Close () ;
m_SingleCallHost = null;
m_SingleSessHost = null;
m_SingletonHost = null;
}
}
}
生成并执行服务
打开命令提示符并执行宿主。这是输出。
现在服务已托管并正在运行,让我们创建客户端,它实际上将使用此服务。
创建客户端
创建基本项目
选择一个基于控制台的应用程序。
生成代理
当宿主应用程序正在运行时,右键单击客户端应用程序项目,然后单击
为 SingleCallService 生成代理。
引用 -> 添加服务引用
在地址栏中,输入 SingleCallService
的 **mex** 终结点地址,如下所示。
在命名空间中,输入一个好的名称,例如 SingleCallServiceReference
。
单击“确定”,这将简单地将一个新文件app.config添加到项目中。并在项目中的“服务引用”节点下添加一个新项。
为 SessionService 生成代理。
引用 -> 添加服务引用
在地址栏中,输入 SessionService
的 **mex** 终结点地址,如下所示。
在命名空间中,输入一个好的名称,例如 SessionServiceReference
。
为 SingletonService 生成代理。
引用 -> 添加服务引用
在地址栏中,输入 SingletonService
的 **mex** 终结点地址,如下所示。
在命名空间中,输入一个好的名称,例如 SingletonServiceReference
。
现在,当您添加了所有 3 个服务的引用后,让我们编写客户端代码来使用这些服务。
// Listing of Program.cs
using System;
using System.Text;
namespace InstanceClient
{
class Program
{
static void Main(string[] args)
{
SingleCallServiceReference.SingleCallServiceClient objSvc1 =
new SingleCallServiceReference.SingleCallServiceClient("WSHttpBinding_ISingleCallService");
SingleCallServiceReference.SingleCallServiceClient objSvc2 =
new SingleCallServiceReference.SingleCallServiceClient("NetTcpBinding_ISingleCallService");
Console.WriteLine("Client 1 Calling Single Call Service 3 times Using Http Binding");
for (int nI = 0; nI < 3; nI++)
{
double dblValue1 = 10;
double dblResult1 = objSvc1.AddValue(dblValue1);
Console.WriteLine("Using HTTP Binding >>
Input Value : {0:F2} Return value : {1:F2}", dblValue1, dblResult1);
}
Console.WriteLine("Client 2 Calling Single Call Service 3 times using TCP Binding");
for (int nI = 0; nI < 3; nI++)
{
double dblValue2 = 10;
double dblResult2 = objSvc2.AddValue(dblValue2);
Console.WriteLine("Using TCP Binding >>
Input Value : {0:F2} Return value : {1:F2}", dblValue2, dblResult2);
}
SessionServiceReference.SessionServiceClient objSvc3 =
new SessionServiceReference.SessionServiceClient("WSHttpBinding_ISessionService");
SessionServiceReference.SessionServiceClient objSvc4 =
new SessionServiceReference.SessionServiceClient("NetTcpBinding_ISessionService");
Console.WriteLine("\n\nClient 1 Calling Single Session Service 3 times Using Http Binding");
for (int nI = 0; nI < 3; nI++)
{
double dblValue1 = 10;
double dblResult1 = objSvc3.AddValue(dblValue1);
Console.WriteLine("Using HTTP Binding >>
Input Value : {0:F2} Return value : {1:F2}", dblValue1, dblResult1);
}
Console.WriteLine("Client 2 Calling Single Session Service 3 times using TCP Binding");
for (int nI = 0; nI < 3; nI++)
{
double dblValue2 = 10;
double dblResult2 = objSvc4.AddValue(dblValue2);
Console.WriteLine("Using TCP Binding >>
Input Value : {0:F2} Return value : {1:F2}", dblValue2, dblResult2);
}
SingletonServiceReference.SingletonServiceClient objSvc5 =
new SingletonServiceReference.SingletonServiceClient("WSHttpBinding_ISingletonService");
SingletonServiceReference.SingletonServiceClient objSvc6 =
new SingletonServiceReference.SingletonServiceClient("NetTcpBinding_ISingletonService");
Console.WriteLine("\n\nClient 1 Calling Singleton Service 3 times Using Http Binding");
for (int nI = 0; nI < 3; nI++)
{
double dblValue1 = 10;
double dblResult1 = objSvc5.AddValue(dblValue1);
Console.WriteLine("Using HTTP Binding >>
Input Value : {0:F2} Return value : {1:F2}", dblValue1, dblResult1);
}
Console.WriteLine("Client 2 Calling Singleton Service 3 times using TCP Binding");
for (int nI = 0; nI < 3; nI++)
{
double dblValue2 = 10;
double dblResult2 = objSvc6.AddValue(dblValue2);
Console.WriteLine("Using TCP Binding >>
Input Value : {0:F2} Return value : {1:F2}", dblValue2, dblResult2);
}
Console.WriteLine("Press any key to close . . . ");
Console.ReadKey();
}
}
}
打开命令提示符并执行客户端以查看输出。
打开另一个命令提示符,并执行客户端的另一个实例。
从输出中可以看出,所有实例模式都在运行。