WCF Dispose()不使用InstanceContectMode = PerSession调用

时间:2012-06-14 17:30:43

标签: .net wcf

在PerSession中如何让服务上的Dispose()触发?在下面的代码中,不会调用Dispose()。当我调用.Close()时,也不会让会话超时。

如果我将服务更改为PerCall,则调用Dispose()(每次调用方法)。使用PerSession,我得到一个会话(使用serviceStartTime测试)。

服务

[ServiceBehavior (InstanceContextMode=InstanceContextMode.PerSession)]
public class MagicEightBallService : IEightBall, IDisposable
{
    private DateTime serviceStartTime;
    public void Dispose()
    {
        Console.WriteLine("Eightball dispose ... " + OperationContext.Current.SessionId.ToString());
    }
    public MagicEightBallService()
    {
        serviceStartTime = DateTime.Now;
        Console.WriteLine("Eightball awaits your question " + OperationContext.Current.SessionId.ToString() + " " + serviceStartTime.ToLongTimeString());
    }
    public string ObtainAnswerToQuestion(string userQuestion)
    {
        return "maybe " + OperationContext.Current.SessionId.ToString() + " " + serviceStartTime.ToLongTimeString();
    }

客户端

    using (EightBallClient ball = new EightBallClient())
    {    
        while (true)
        {
            Console.Write("Your question: ");
            string question = Console.ReadLine();
            if (string.IsNullOrEmpty(question)) break;
            try
            {
                string answer = ball.ObtainAnswerToQuestion(question);
                Console.WriteLine("8-ball says: {0}", answer);
            }
            catch (Exception Ex)
            {
                Console.WriteLine("ball.ObtainAnswerToQuestion exception " + Ex.Message);
            }               
        }
        ball.Close();
     }

服务合同

[ServiceContract (SessionMode = SessionMode.Required)]
public interface IEightBall
{
    [OperationContract]
    string ObtainAnswerToQuestion(string userQuestion);

    [OperationContract]
    sDoc GetSdoc(int sID);

    DateTime CurDateTime();
}

主机

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <bindings>
      <wsHttpBinding>
        <binding name="WSHttpBinding_ISampleService" 
                 closeTimeout="00:01:00" openTimeout="00:01:00" 
                 receiveTimeout="00:10:00" sendTimeout="00:10:00">
          <security mode="Message" />
          <reliableSession ordered="true"
                   inactivityTimeout="00:10:00"
                   enabled="true" />
        </binding>
      </wsHttpBinding>
    </bindings>
    <services>
      <service name="MajicEightBallServiceLib.MagicEightBallService"
               behaviorConfiguration="EightBallServiceMEXBehavior" >
        <endpoint address=""
                  binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_ISampleService"
                  contract="MajicEightBallServiceLib.IEightBall">
        </endpoint>
        <endpoint address="mex"
                  binding ="mexHttpBinding"
                  contract="IMetadataExchange" />
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8000/MagicEightBallService"/>
          </baseAddresses>
        </host>             
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="EightBallServiceMEXBehavior">
          <serviceMetadata httpGetEnabled="true"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>

namespace MagicEightBallServiceHost
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("**** Console Based WCF Host *****");

            using (ServiceHost serviceHost = new ServiceHost(typeof(MagicEightBallService)))
            {
                serviceHost.Open();
                Console.WriteLine("The service is running");
                Console.ReadLine();
            }
        }
    }
}

1 个答案:

答案 0 :(得分:10)

Dispose()方法将被解雇。唯一的问题是“什么时候?”。

对该问题的回答取决于服务配置。

有几种可能的情况:

  1. 绑定不支持会话
  2. 正常会话
  3. 可靠的会话
  4. 会话关闭Dispose()上下文模式时会触发

    PerSession。所以我们需要检查会话在不同场景中的生存时间。

    对于某些配置(例如默认BasicHttpBinding),会话根本不会启动。如果无会话配置PerCallPerSession上下文模式没有区别,并且在执行主方法后很快就会调用Dispose方法。

    Session启用时,客户端或超时可以显式关闭它。通常它由客户控制。客户端在首次调用服务之前启动会话,并在关闭客户端对象时关闭它。

    ServiceClient proxy = new ServiceClient();
    Console.WriteLine(proxy.GetData(123));
    proxy.Close();  
    
    上面的

    proxy.Close()方法会关闭服务器中的会话,而会话又会执行Dispose()

    会话管理是一个很大的性能驱动因素,因为它需要在客户端和服务器之间执行额外的调用。

    因此,当客户希望关闭会话时,通常会调用Dispose

    如果客户因任何原因没有关闭会话,服务主机将在一段时间后关闭会话。该期间由Binding.ReceiveTimeout属性控制。 该属性的默认值为10分钟。

    如果没有人向具有特定会话ID的服务器发送请求10分钟,会话将被关闭并且(Dispose()被解雇)。 可以通过在web.config中将receiveTimeout设置为更短的值来更改此默认超时。

    <wsHttpBinding>
      <binding name="wsHttpEndpointBinding" receiveTimeout="00:00:05">
      </binding>
    </wsHttpBinding> 
    
    启用Reliable会话时,还会检查

    ReliableSession.InactivityTimeout。它也默认为10分钟。

    它在自托管和IIS托管服务中按预期工作。

    尝试按以下方式更新客户端代码以进行测试:

    using (EightBallClient ball = new EightBallClient())
    {    
        ball.ObtainAnswerToQuestion("test");
        ball.Close();
    }