• WCF 实例模式和对象生命周期


     1、WCF 几种服务对象实例创建模式

    wcf中有三种服务对象实例创建模式:PerCall、PerSession、Single.(具体在哪里设置,最后例子中有很好的阐述)

    2、几种模式下服务对象实例的生命周期(这里暂不考虑Mep)

     PerCall模式

      PerCall模式工作流程如下

    •    客户端创建代理对象(Proxy)
    •    客户端调用代理对象的一个契约操作,代理对象将其传递给服务宿主程序
    •    宿主应用程序创建一新的服务契约对象,并且执行请求操作
    •    在执行完请求操作后,如果要求有应答,那么服务契约会给代理对象一个应答,然后销毁自己

      示例代码展示

      服务契约代码如下:

     

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;

    namespace Contract
    {
    [ServiceContract(Name="CalculatorService",Namespace="http://www/gxs.com")]
    public interface ICalculator:IDisposable
    {
    [OperationContract(Name = "CalculatorAdd")]
    double Add(double x, double y);
    [OperationContract(Name = "CalculatorSubtract")]
    double Subtract(double x, double y);
    }
    }

    服务代码如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using Contract;
    using System.ServiceModel;

    namespace Service
    {
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    public class CalculatorPerCall:ICalculator
    {
    public CalculatorPerCall()
    {
    Console.WriteLine("Create a new instance!!!");
    }
    public double Add(double x, double y)
    {
    Console.WriteLine("Call [Add] Method");
    return x + y;
    }
    public double Subtract(double x, double y)
    {
    Console.WriteLine("Call [Subtract] Method");
    return x - y;
    }
    public void Dispose()
    {
    Console.WriteLine("The instance has been disposed!!!");
    }
    }
    }

     

    服务端宿主代码如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;
    using Contract;
    using Service;
    using System.ServiceModel.Description;

    namespace Hosting
    {
    class Program
    {
    static void Main(string[] args)
    {
    using (ServiceHost host = new ServiceHost(typeof(CalculatorPerCall)))
    {
    host.AddServiceEndpoint(typeof(ICalculator), new WSHttpBinding(), "http://127.0.0.1:8089/CalculatorService");
    //ServiceMetadataBehavior:控制服务元数据和相关信息的发布
    if (host.Description.Behaviors.Find<ServiceMetadataBehavior>() == null)
    {
    ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();
    behavior.HttpGetEnabled = true;
    behavior.HttpGetUrl = new Uri("http://127.0.0.1:8089/CalculatorService/metadata");
    host.Description.Behaviors.Add(behavior);
    }
    host.Opened += new EventHandler(host_Opened);
    host.Open();
    Console.Read();
    }
    }

    static void host_Opened(object sender, EventArgs e)
    {
    Console.WriteLine("计算机服务已经被打开了......");
    }
    }
    }



    客户端代码如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    namespace WcfLifeCycle.Client
    {
    /// <summary>
    /// wcf实例模型
    /// </summary>
    public class ClientCalculator
    {
    public static void Main(string[] args)
    {
    CalculatorServiceClient proxy1 = new CalculatorServiceClient();
    Console.WriteLine("proxy1 Call [Add] method");
    proxy1.CalculatorAdd(12d, 13d);
    Console.WriteLine("proxy1 Call [Add] method");
    proxy1.CalculatorAdd(12d, 13d);
    Console.WriteLine("proxy1 Call [Add] method");
    proxy1.CalculatorAdd(12d, 13d);
    Console.WriteLine("******************************************");
    CalculatorServiceClient proxy2= new CalculatorServiceClient();
    Console.WriteLine("proxy2 Call [Add] method");
    proxy2.CalculatorAdd(12d, 13d);
    Console.WriteLine("proxy2 Call [Add] method");
    proxy2.CalculatorAdd(12d, 13d);
    Console.WriteLine("proxy2 Call [Add] method");
    proxy2.CalculatorAdd(12d, 13d);
    Console.Read();
    }
    }
    }

     结果示例图

     服务端:

    客户端

    小结:Percall模式,客户端每次发出请求后,服务端都会生成一个实例响应,响应完毕后自行销毁。

     PerSession模式

    PerSession模式工作的流程如下:

    • 客户端创建代理对象(Proxy) 
    • 客户端第一次调用代理对象的一个契约操作,代理对象将其调用请求传递给服务宿主
    • 宿主程序创建新的服务对象,并执行请求操作,如果有必要,返回客户端应答
    • 客户端再次发出调用操作的请求(图中的proxy一与服务实例一对应,proxy二与服务实例二对应),宿主会先判断是否已有建立好的会话,如果存在,则不需要再创建新的服务对象,直接使用老对象即可,如果不存在则新建一个服务对象。
    • 在时间达到指定要求或者因一些特殊原因,会话会过期,此时服务对象销毁.或者客户端关闭,服务对象也会自动销毁。

    示例代码展示

      服务契约代码如下:

    View Code
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;

    namespace Contract
    {
    [ServiceContract(Name="CalculatorService",Namespace="http://www/gxs.com")]
    public interface ICalculator:IDisposable
    {
    [OperationContract(Name = "CalculatorAdd")]
    double Add(double x, double y);
    [OperationContract(Name = "CalculatorSubtract")]
    double Subtract(double x, double y);
    }
    }

    服务代码如下:

    View Code
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using Contract;
    using System.ServiceModel;

    namespace Service
    {
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
    public class CalculatorPerSession : ICalculator
    {
    public CalculatorPerSession()
    {
    Console.WriteLine("Create a new instance!!!");
    }
    public double Add(double x, double y)
    {
    Console.WriteLine("Call [Add] Method");
    return x + y;
    }
    public double Subtract(double x, double y)
    {
    Console.WriteLine("Call [Subtract] Method");
    return x - y;
    }
    public void Dispose()
    {
    Console.WriteLine("The instance has been disposed!!!");
    }
    }
    }


    服务端宿主代码

    View Code
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;
    using Contract;
    using Service;
    using System.ServiceModel.Description;

    namespace Hosting
    {
    class Program
    {
    static void Main(string[] args)
    {
    using (ServiceHost host = new ServiceHost(typeof(CalculatorPerSession)))
    {
    host.AddServiceEndpoint(typeof(ICalculator), new WSHttpBinding(), "http://127.0.0.1:8089/CalculatorService");
    //ServiceMetadataBehavior:控制服务元数据和相关信息的发布
    if (host.Description.Behaviors.Find<ServiceMetadataBehavior>() == null)
    {
    ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();
    behavior.HttpGetEnabled = true;
    behavior.HttpGetUrl = new Uri("http://127.0.0.1:8089/CalculatorService/metadata");
    host.Description.Behaviors.Add(behavior);
    }
    host.Opened += new EventHandler(host_Opened);
    host.Open();
    Console.Read();
    }
    }
    static void host_Opened(object sender, EventArgs e)
    {
    Console.WriteLine("计算机服务已经被打开了......");
    }
    }
    }


    客户端代码如下:

    View Code
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    namespace WcfLifeCycle.Client
    {
    /// <summary>
    /// wcf实例模型
    /// </summary>
    public class ClientCalculator
    {
    public static void Main(string[] args)
    {
    CalculatorServiceClient proxy1 = new CalculatorServiceClient();
    Console.WriteLine("proxy1 Call [Add] method");
    proxy1.CalculatorAdd(12d, 13d);
    Console.WriteLine("proxy1 Call [Add] method");
    proxy1.CalculatorAdd(12d, 13d);
    Console.WriteLine("proxy1 Call [Add] method");
    proxy1.CalculatorAdd(12d, 13d);
    Console.WriteLine("******************************************");
    CalculatorServiceClient proxy2= new CalculatorServiceClient();
    Console.WriteLine("proxy2 Call [Add] method");
    proxy2.CalculatorAdd(12d, 13d);
    Console.WriteLine("proxy2 Call [Add] method");
    proxy2.CalculatorAdd(12d, 13d);
    Console.WriteLine("proxy2 Call [Add] method");
    proxy2.CalculatorAdd(12d, 13d);
    Console.Read();
    }
    }
    }


    结果实例图

    服务端

    客户端

    小结:PerSession模式,proxy与服务实例对应。不同的proxy有不同的服务实例。

    Single模式

    Single模式的工作流程如下:

    • 服务端启动,同时创建服务对象
    • 客户端通过代理调用契约操作
    • 第一步中创建的服务对象接受请求 ,并执行操作,进行必要的应答
    • 第一步创建的服务对象将一直保留
    • 服务关闭,第一步创建的对象销毁

    示例代码展示:

    服务契约代码

     

    View Code
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;

    namespace Contract
    {
    [ServiceContract(Name="CalculatorService",Namespace="http://www/gxs.com")]
    public interface ICalculator:IDisposable
    {
    [OperationContract(Name = "CalculatorAdd")]
    double Add(double x, double y);
    [OperationContract(Name = "CalculatorSubtract")]
    double Subtract(double x, double y);
    }
    }

     
    服务代码

    View Code
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using Contract;
    using System.ServiceModel;

    namespace Service
    {
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    public class CalculatorPerSingle : ICalculator
    {
    public CalculatorPerSingle()
    {
    Console.WriteLine("Create a new instance!!!");
    }
    public double Add(double x, double y)
    {
    Console.WriteLine("Call [Add] Method");
    return x + y;
    }
    public double Subtract(double x, double y)
    {
    Console.WriteLine("Call [Subtract] Method");
    return x - y;
    }
    public void Dispose()
    {
    Console.WriteLine("The instance has been disposed!!!");
    }
    }
    }

    服务端宿主代码

    View Code
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;
    using Contract;
    using Service;
    using System.ServiceModel.Description;

    namespace Hosting
    {
    class Program
    {
    static void Main(string[] args)
    {
    using (ServiceHost host = new ServiceHost(typeof(CalculatorPerSingle), new Uri("http://127.0.0.1:8089")))
    {
    host.AddServiceEndpoint(typeof(ICalculator), new WSHttpBinding(), "CalculatorServiceOne");
    host.AddServiceEndpoint(typeof(ICalculator), new WSHttpBinding(), "CalculatorServiceTwo");
    //ServiceMetadataBehavior:控制服务元数据和相关信息的发布
    if (host.Description.Behaviors.Find<ServiceMetadataBehavior>() == null)
    {
    ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();
    behavior.HttpGetEnabled = true;
    behavior.HttpGetUrl = new Uri("http://127.0.0.1:8089/CalculatorService/metadata");
    host.Description.Behaviors.Add(behavior);
    }
    host.Opened += new EventHandler(host_Opened);
    host.Open();
    Console.Read();
    }
    }
    static void host_Opened(object sender, EventArgs e)
    {
    Console.WriteLine("计算机服务已经被打开了......");
    }
    }
    }


    客户端一代码

    View Code
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    namespace WcfLifeCycle.Client
    {
    /// <summary>
    /// wcf实例模型
    /// </summary>
    public class ClientOneCalculator
    {
    public static void Main(string[] args)
    {
    CalculatorServiceClient proxy1 = new CalculatorServiceClient("WSHttpBinding_CalculatorService");
    Console.WriteLine("I am EndPointOne");
    Console.WriteLine("proxy1 Call [Add] method");
    proxy1.CalculatorAdd(12d, 13d);
    Console.WriteLine("proxy1 Call [Add] method");
    proxy1.CalculatorAdd(12d, 13d);
    Console.WriteLine("proxy1 Call [Add] method");
    proxy1.CalculatorAdd(12d, 13d);
    proxy1.Close();
    Console.Read();
    }
    }
    }

    客户端一配置文件app.config

    View Code
    <?xml version="1.0"?>
    <configuration>
    <system.serviceModel>
    <bindings>
    <wsHttpBinding>
    <binding name="WSHttpBinding_CalculatorService" closeTimeout="00:01:00"
    openTimeout
    ="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
    bypassProxyOnLocal
    ="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
    maxBufferPoolSize
    ="524288" maxReceivedMessageSize="65536"
    messageEncoding
    ="Text" textEncoding="utf-8" useDefaultWebProxy="true"
    allowCookies
    ="false">
    <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
    maxBytesPerRead
    ="4096" maxNameTableCharCount="16384" />
    <reliableSession ordered="true" inactivityTimeout="00:10:00"
    enabled
    ="false" />
    <security mode="Message">
    <transport clientCredentialType="Windows" proxyCredentialType="None"
    realm
    ="" />
    <message clientCredentialType="Windows" negotiateServiceCredential="true"
    algorithmSuite
    ="Default" />
    </security>
    </binding>
    <binding name="WSHttpBinding_CalculatorService1" closeTimeout="00:01:00"
    openTimeout
    ="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
    bypassProxyOnLocal
    ="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
    maxBufferPoolSize
    ="524288" maxReceivedMessageSize="65536"
    messageEncoding
    ="Text" textEncoding="utf-8" useDefaultWebProxy="true"
    allowCookies
    ="false">
    <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
    maxBytesPerRead
    ="4096" maxNameTableCharCount="16384" />
    <reliableSession ordered="true" inactivityTimeout="00:10:00"
    enabled
    ="false" />
    <security mode="Message">
    <transport clientCredentialType="Windows" proxyCredentialType="None"
    realm
    ="" />
    <message clientCredentialType="Windows" negotiateServiceCredential="true"
    algorithmSuite
    ="Default" />
    </security>
    </binding>
    </wsHttpBinding>
    </bindings>
    <client>
    <endpoint address="http://127.0.0.1:8089/CalculatorServiceOne"
    binding
    ="wsHttpBinding" bindingConfiguration="WSHttpBinding_CalculatorService"
    contract
    ="Client.CalculatorService" name="WSHttpBinding_CalculatorService">
    <identity>
    <userPrincipalName value="guxiaoshi-PC\guxiaoshi" />
    </identity>
    </endpoint>
    <endpoint address="http://127.0.0.1:8089/CalculatorServiceTwo"
    binding
    ="wsHttpBinding" bindingConfiguration="WSHttpBinding_CalculatorService1"
    contract
    ="Client.CalculatorService" name="WSHttpBinding_CalculatorService1">
    <identity>
    <userPrincipalName value="guxiaoshi-PC\guxiaoshi" />
    </identity>
    </endpoint>
    </client>
    </system.serviceModel>
    <startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>

    客户端二代码

    View Code
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using ClientTwo.Client;

    namespace ClientTwo
    {
    class ClientTwoCalculator
    {
    static void Main(string[] args)
    {
    CalculatorServiceClient proxy1 = new CalculatorServiceClient("WSHttpBinding_CalculatorService1");
    Console.WriteLine("I am EndPointTwo");
    Console.WriteLine("proxy1 Call [Add] method");
    proxy1.CalculatorAdd(12d, 13d);
    Console.WriteLine("proxy1 Call [Add] method");
    proxy1.CalculatorAdd(12d, 13d);
    Console.WriteLine("proxy1 Call [Add] method");
    proxy1.CalculatorAdd(12d, 13d);
    proxy1.Close();
    Console.Read();
    }
    }
    }

    客户端二配置文件app.config

    View Code
    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
    <system.serviceModel>
    <bindings>
    <wsHttpBinding>
    <binding name="WSHttpBinding_CalculatorService" closeTimeout="00:01:00"
    openTimeout
    ="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
    bypassProxyOnLocal
    ="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
    maxBufferPoolSize
    ="524288" maxReceivedMessageSize="65536"
    messageEncoding
    ="Text" textEncoding="utf-8" useDefaultWebProxy="true"
    allowCookies
    ="false">
    <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
    maxBytesPerRead
    ="4096" maxNameTableCharCount="16384" />
    <reliableSession ordered="true" inactivityTimeout="00:10:00"
    enabled
    ="false" />
    <security mode="Message">
    <transport clientCredentialType="Windows" proxyCredentialType="None"
    realm
    ="" />
    <message clientCredentialType="Windows" negotiateServiceCredential="true"
    algorithmSuite
    ="Default" />
    </security>
    </binding>
    <binding name="WSHttpBinding_CalculatorService1" closeTimeout="00:01:00"
    openTimeout
    ="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
    bypassProxyOnLocal
    ="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
    maxBufferPoolSize
    ="524288" maxReceivedMessageSize="65536"
    messageEncoding
    ="Text" textEncoding="utf-8" useDefaultWebProxy="true"
    allowCookies
    ="false">
    <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
    maxBytesPerRead
    ="4096" maxNameTableCharCount="16384" />
    <reliableSession ordered="true" inactivityTimeout="00:10:00"
    enabled
    ="false" />
    <security mode="Message">
    <transport clientCredentialType="Windows" proxyCredentialType="None"
    realm
    ="" />
    <message clientCredentialType="Windows" negotiateServiceCredential="true"
    algorithmSuite
    ="Default" />
    </security>
    </binding>
    </wsHttpBinding>
    </bindings>
    <client>
    <endpoint address="http://127.0.0.1:8089/CalculatorServiceOne"
    binding
    ="wsHttpBinding" bindingConfiguration="WSHttpBinding_CalculatorService"
    contract
    ="Client.CalculatorService" name="WSHttpBinding_CalculatorService">
    <identity>
    <userPrincipalName value="guxiaoshi-PC\guxiaoshi" />
    </identity>
    </endpoint>
    <endpoint address="http://127.0.0.1:8089/CalculatorServiceTwo"
    binding
    ="wsHttpBinding" bindingConfiguration="WSHttpBinding_CalculatorService1"
    contract
    ="Client.CalculatorService" name="WSHttpBinding_CalculatorService1">
    <identity>
    <userPrincipalName value="guxiaoshi-PC\guxiaoshi" />
    </identity>
    </endpoint>
    </client>
    </system.serviceModel>
    </configuration>

    结果实例图

    服务端

    客户端一

    客户端二

    小结:服务端自始至终只有一个实例与客户端进行消息的交换。

    总结:上文是对服务对象实例生命周期的介绍.Percall:新的请求产生新的服务对象与之交换信息,服务对象自行销毁;PerSession:相同的客户端由同一个服务对象与之交换信息(这里的客户端指proxy);Single:服务端只有一个服务实例,服务打开时服务实例就会被创建。

  • 相关阅读:
    *** 82 删除排序链表中的重复元素II
    83 删除排序链表中的重复元素
    61 旋转链表
    ASP.NET MVC3 ModelState.IsValid为false的问题
    ServletContext
    ServletConfig
    Servlet线程安全
    Servlet的一些细节(2)
    Servlet的一些细节(1)
    Servlet的接口实现类
  • 原文地址:https://www.cnblogs.com/smallstone/p/2277194.html
Copyright © 2020-2023  润新知