I need to create a service which will maintain a WCF session.
In the constructor I read in data from the DB and when the session ends I have to save it back.
If I understand correctly the session ends when I call Close() on the Client (My client ServiceClient was created with SvcUtil.exe).
When I test it I see that it is sometimes called after approx. 10 minutes, sometimes after 20 minutes and sometimes not at all.
So when is the destructor called?
Service
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class Service:IService
{
private User m_User = null;
public Service()
{
m_User = User.LoadFromDB();
}
~Service()
{
m_User.SaveToDB();
}
public void SetName(string p_Name)
{
m_User.Name = p_Name;
}
}
Web.config
<?xml version="1.0"?>
<configuration>
<system.web>
<sessionState timeout="2" />
</system.web>
<system.serviceModel>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
<services>
<service name="Karatasi.Services.B2C" behaviorConfiguration="ServiceBehavior">
<host>
<baseAddresses>
<add baseAddress="http://localhost:19401/B2C.svc"/>
</baseAddresses>
</host>
<endpoint
address=""
binding="wsHttpBinding"
bindingConfiguration="test"
contract="Karatasi.Services.IB2C"
/>
<endpoint
address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange"
/>
</service>
</services>
<bindings>
<wsHttpBinding>
<binding name="test" receiveTimeout="00:01:00" >
<reliableSession enabled="true" ordered="false" inactivityTimeout="00:01:00"/>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
Client
ServiceClient serviceClient = null;
try
{
serviceClient = new ServiceClient();
serviceClient.SetName("NewName");
Console.WriteLine("Name set");
}
catch (Exception p_Exc)
{
Console.WriteLine(p_Exc.Message);
}
finally
{
if (serviceClient != null)
{
if (serviceClient.State == CommunicationState.Faulted)
{
serviceClient.Abort();
}
else
{
serviceClient.Close();
}
}
Console.ReadKey();
}
From docs
There is a problem with your implementation. To persist data you are using destructor. This is wrong because destructors cannot be called deterministically, they are processed in a separate finalization queue. This means that even though you have destroyed the object, its destructor may not be immediately called.
How to fix this
Remove the destructor and use IDisposable pattern instead, put save logic into Dispose. Once the session is terminated, WCF will call IDisposable.Dispose
EDIT
Pls also see the comment to this answer. I actually agree that
IDisposableisn’t the proper place for database commits, didn’t occur to me before. Additionally to the solutions provided in the comment you can use explicit session demarcation