admin - 2008-6-14 18:34:00
WCF Reliable Sessions Puzzle(解决:System.ServiceModel.Channels.ServiceChannel)íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
As I mentioned on my previous post, I have spent a few days very puzzled with a behaviour in WCF reliable messaging/sessions.íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
THe problem all starts because as documented here, creating WCF clients (the classes generated by svcutil.exe) is quite expensive due to the rich set of functionality implemented in WCF. You can learn more about the client model here. To overcome the problem, there are basically two options:íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
- Create aChannelFactory instance and keep that in the application contextsomewhere, so you don't have to initialize the factory every time youneed a client. You then use this factory to create client channelsdirectly;
- Create a client instance and cache that to be reused for multiple calls.
Ultimatelly, option 2offers the best performance, as you go through the expense ofinstantiating the client only once. I then wrote a pool class to managea number of client instances and all was nice and cool until theclients' connections started to be closed by the WCF host due toinactivity (I'm using NetTcp binding). As my application is the onlyone to use my WCF service and I can control the number of clientconnections open to the host at one time, I wanted just to keep theseconnections alive for as long as the client application lived, so Ithought about using Reliable Sessions for that. Basically, asdocumented here, reliable sessions are kept alive by the WCF architecture indefinitely, so that's good for what I need.íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
The weird thing started whenafter enabling reliable sessions in my app, the behaviour of the hostdidn't change: it would still drop my connections after 10 minutes andeverything would go bad. I then wrote some simple code to try toreplicate the problem, code that can be seen below:íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
using System;íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰiusing System.ServiceModel;íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰinamespace ServiceíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi{íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰiíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
[ServiceContract(SessionMode = SessionMode.Allowed,íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰiíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
Namespace = "http://tempuri.org/Services/IServiceContract")]íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰiíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
public interface IServiceContractíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰiíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
{íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰiíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
[OperationContract]íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰiíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
string DoSomething(string arg);íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰiíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
}íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰiíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
[ServiceBehavior(Namespace = "http://tempuri.org/Services/ServiceImplementation")]íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰiíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
public class ServiceImplementation : IServiceContractíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰiíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
{íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰiíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
#region IServiceContract MembersíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰiíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
public string DoSomething(string arg)íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰiíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
{íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰiíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
return string.Format("The string passed in was '{0}'.", arg);íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰiíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
}íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰiíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
#endregioníS
¾
£Hª;www.netcsharp.cnÅÑà×AŰiíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
}íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰiíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
class ProgramíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰiíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
{íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰiíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
static void Main(string[] args)íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰiíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
{íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰiíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
using (ServiceHost serviceHost = new ServiceHost(typeof(ServiceImplementation)))íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰiíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
{íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰiíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
serviceHost.Open();íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰiíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
Console.WriteLine("Service running. Press any key to exit.");íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰiíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
Console.Read();íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰiíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
serviceHost.Close();íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰiíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
}íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰiíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
}íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰiíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
}íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi}íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰiíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰiThe configuration file for the service looks like the following:íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰiíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi<?xmlíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
version="1.0"íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
encoding="utf-8" ?>íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
<configuration>íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
<system.serviceModel>íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
<bindings>íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
<netTcpBinding>íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
<bindingíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
name="NetTcp_Reliable">íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
<reliableSessioníS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
ordered="false"íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
inactivityTimeout="00:10:00"íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
enabled="true" />íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
</binding>íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
</netTcpBinding>íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
</bindings>íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
<behaviors>íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
<serviceBehaviors>íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
<behavioríS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
name="MetadataBehavior">íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
<serviceMetadataíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
httpGetEnabled="true"íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
httpGetUrl="http://localhost:2526/Service" />íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
</behavior>íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
</serviceBehaviors>íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
</behaviors>íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
<services>íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
<serviceíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
behaviorConfiguration="MetadataBehavior"íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
name="Service.ServiceImplementation">íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
<endpointíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
address="net.tcp://localhost:2525/Service"íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
binding="netTcpBinding"íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
bindingConfiguration="NetTcp_Reliable"íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
contract="Service.IServiceContract" />íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
</service>íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
</services>íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
</system.serviceModel>íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
</configuration>íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
Forthe client application I have used svcutil.exe to generate the WCFclient and the configuration file. The client is pretty ordinary and Ihaven’t changed anything so I will spare you the bore of reading it,but the config file looked like this:íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
<?xmlíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
version="1.0"íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
encoding="utf-8"?>íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
<configuration>íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
<system.serviceModel>íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
<bindings>íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
<netTcpBinding>íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
<bindingíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
name="NetTcpBinding_IServiceContract"íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
closeTimeout="00:01:00"íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
openTimeout="00:01:00"íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
receiveTimeout="00:10:00"íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
sendTimeout="00:01:00"íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
transactionFlow="false"íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
transferMode="Buffered"íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
transactionProtocol="OleTransactions"íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
hostNameComparisonMode="StrongWildcard"íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
listenBacklog="10"íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
maxBufferPoolSize="524288"íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
maxBufferSize="65536"íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
maxConnections="10"íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
maxReceivedMessageSize="65536">íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
<readerQuotasíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
maxDepth="32"íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
maxStringContentLength="8192"íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
maxArrayLength="16384"íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
maxBytesPerRead="4096"íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
maxNameTableCharCount="16384" />íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
<reliableSessioníS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
ordered="false"íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
inactivityTimeout="00:10:00"íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
enabled="true" />íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
<securityíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
mode="Transport">íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
<transportíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
clientCredentialType="Windows"íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
protectionLevel="EncryptAndSign" />íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
<messageíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
clientCredentialType="Windows" />íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
</security>íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
</binding>íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
</netTcpBinding>íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
</bindings>íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
<client>íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
<endpointíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
address="net.tcp://localhost:2525/Service"íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
binding="netTcpBinding"íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
bindingConfiguration="NetTcpBinding_IServiceContract"íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
contract="IServiceContract"íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
name="NetTcpBinding_IServiceContract">íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
</endpoint>íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
</client>íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
</system.serviceModel>íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
</configuration>íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
Thesesettings are pretty much the defaults for NetTcp binding except for thereliableSession element that enables RM and disables message ordering.The console application that uses the WCF client looks like thefollowing:íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
namespace ClientíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
{íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
class ProgramíS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
{íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
static void Main(string[] args)íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
{íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
ServiceContractClient client = new ServiceContractClient();íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
client.InnerChannel.Faulted += new EventHandler(InnerChannel_Faulted);íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
Console.WriteLine("The call was made at {0} and the response was '{1}'", DateTime.Now, client.DoSomething("First Call"));íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
Console.WriteLine("Press any key to call the server again!");íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
Console.Read();íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
Console.WriteLine("The call was made at {0} and the response was '{1}'", DateTime.Now, client.DoSomething("Second Call"));íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
Console.Read();íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
}íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
static void InnerChannel_Faulted(object sender, EventArgs e)íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
{íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
Console.WriteLine("The channel faulted!");íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
}íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
}íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
}íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
Theabove console application allowed me to let the application hit theservice once, then I could leave it idle for as much as I wanted andtry to hit the service again after pressing any key. It will alsohandle the Faulted event in the client’s inner channel. The behaviour Iwas expecting is that regardless of how long I left the applicationidle after the first call to the service, when I pressed a key I wouldstill be able to call the service again. What happenned instead is thatafter 10 minutes of the application iddle, the Faulted event of thechannel would be raised, telling me that the connection was gone.íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
Myfirst thought was to increase the InactivityTimeout on the reliablesession configuration in both client and server to 20 minutes insteadof 10 and see what happened. When running the application it wouldstill fault the channel after 10 minutes. íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
Afterposting in the WCF forums I was pointed to the Receive Timeout in thebinding configuration. After reading the extensive (NOT) documentationavailable for this property I was led to believe that it was the timealowed for a receive operation (i.e. the time the client takes to senda full message stream) to be completed, but in reality this property isthe time the service allows between client calls(poor, poor documentation Microsoft). Even though, my understanding wasthat the WCF infrastructure messages exchanged by RM to keep thesession alive would count for this receive timeout and would keep myconnection alive, but that evidently wasn’t happening.íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
Wethen contacted Microsoft PSS and after a while they confirmed that thebehavior should be that the infrastructure messages keep the connectionalive, but they have changed something in the receive timeout behaviourclose to RTM and the end result was that this setting overrideseverything else (all other timeouts or sessions) in WCF. It isrecognised within Microsoft as a bug, which is good: they know aboutthe bug… but the bad news are that they don’t plan to fix it before WCFversion 2.0 as they believe there’s a viable workaround. The workaroundin this case is that you can set the receive timeout to an extremelylong time span (or System.TimeSpan.MaxValue) or the infinite keyword(that behind the scenes will use System.TimeSpan.MaxValue) and it willproduce the expected behaviour.íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
Moralof the story is: if you ever use WCF reliable messaging and need thesession to be kept alive indefinitely you already know: set the receivetimeout to something very, very big. íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi
íS
¾
£Hª;www.netcsharp.cnÅÑà×AŰi