在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();
}
}
}
}
答案 0 :(得分:10)
Dispose()
方法将被解雇。唯一的问题是“什么时候?”。
对该问题的回答取决于服务配置。
有几种可能的情况:
Dispose()
上下文模式时会触发 PerSession
。所以我们需要检查会话在不同场景中的生存时间。
对于某些配置(例如默认BasicHttpBinding
),会话根本不会启动。如果无会话配置PerCall
和PerSession
上下文模式没有区别,并且在执行主方法后很快就会调用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();
}