Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When is destructor called in a WCF service

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();
    }
like image 628
Nejchy Avatar asked Sep 03 '11 18:09

Nejchy


People also ask

When should I use Destructor C#?

Destructors in C# are methods inside the class used to destroy instances of that class when they are no longer needed. The Destructor is called implicitly by the . NET Framework's Garbage collector and therefore programmer has no control as when to invoke the destructor.

Do we need to call destructor C#?

Since C# provides garbage collection, you never need to explicitly destroy your objects.

What does a destructor do C#?

In C#, destructor (finalizer) is used to destroy objects of class when the scope of an object ends. It has the same name as the class and starts with a tilde ~ .

Can we use session in WCF service C#?

WCF manage session by creating the instance of the service class. These created instance(s) handle the incoming service request. In WCF, session is the way of managing the services instance(s) so that server can used these instances in an optimized way.


1 Answers

From docs

The programmer has no control over when the destructor is called because this is determined by the garbage collector. The garbage collector checks for objects that are no longer being used by the application. If it considers an object eligible for destruction, it calls the destructor (if any) and reclaims the memory used to store the object. Destructors are also called when the program exits.

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

public class Service:IService, IDisposable
{
    public void Dispose()
    {
        //your save logic here
    }
}

EDIT
Pls also see the comment to this answer. I actually agree that IDisposable isn'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

like image 172
oleksii Avatar answered Sep 21 '22 08:09

oleksii