65.9K
CodeProject 正在变化。 阅读更多。
Home

理解 WCF 中的实例管理

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1投票)

2015 年 1 月 9 日

CPOL

4分钟阅读

viewsIcon

8350

理解 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;
        }
    }
}

生成并执行服务

打开命令提示符并执行宿主。这是输出。

image

现在服务已托管并正在运行,让我们创建客户端,它实际上将使用此服务。

创建客户端

创建基本项目

选择一个基于控制台的应用程序。

生成代理

当宿主应用程序正在运行时,右键单击客户端应用程序项目,然后单击

为 SingleCallService 生成代理。

引用 -> 添加服务引用

在地址栏中,输入 SingleCallService 的 **mex** 终结点地址,如下所示。

image

在命名空间中,输入一个好的名称,例如 SingleCallServiceReference

单击“确定”,这将简单地将一个新文件app.config添加到项目中。并在项目中的“服务引用”节点下添加一个新项。

为 SessionService 生成代理。

引用 -> 添加服务引用

在地址栏中,输入 SessionService 的 **mex** 终结点地址,如下所示。

image

在命名空间中,输入一个好的名称,例如 SessionServiceReference

为 SingletonService 生成代理。

引用 -> 添加服务引用

在地址栏中,输入 SingletonService 的 **mex** 终结点地址,如下所示。

image

在命名空间中,输入一个好的名称,例如 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();
        }
    }
}

打开命令提示符并执行客户端以查看输出。

image

打开另一个命令提示符,并执行客户端的另一个实例。

image

从输出中可以看出,所有实例模式都在运行。

© . All rights reserved.