Когда вызывается деструктор в службе WCF - PullRequest
9 голосов
/ 03 сентября 2011

Мне нужно создать сервис, который будет поддерживать сеанс WCF.В конструкторе я читаю данные из БД, и когда сеанс заканчивается, я должен сохранить его обратно.

Если я правильно понимаю, сеанс заканчивается, когда я вызываю Close () на клиенте (был создан мой клиент ServiceClientс SvcUtil.exe).

Когда я проверяю его, я вижу, что он иногда вызывается после прибл.10 минут, иногда через 20 минут, а иногда и вовсе нет.

Так когда же вызывается деструктор?

Служба

   [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>

Клиент

    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();
    }

1 Ответ

16 голосов
/ 03 сентября 2011

Из документов

Программист не может контролировать, когда вызывается деструктор. потому что это определяется сборщиком мусора. Мусор сборщик проверяет объекты, которые больше не используются приложение. Если он считает, что объект подлежит уничтожению, он вызывает деструктор (если есть) и восстанавливает память, используемую для хранения предмет. Деструкторы также вызываются при выходе из программы.

Проблема с вашей реализацией. Для сохранения данных вы используете деструктор. Это неправильно, потому что деструкторы нельзя вызывать детерминистически, они обрабатываются в отдельной очереди завершения. Это означает, что даже если вы уничтожили объект, его деструктор может быть вызван не сразу.

Как это исправить
Удалите деструктор и используйте вместо этого шаблон IDisposable, поместите логику сохранения в Dispose. После завершения сеанса WCF вызовет IDisposable.Dispose

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

EDIT
Просьба также увидеть комментарий к этому ответу. Я действительно согласен с тем, что IDisposable не является подходящим местом для фиксации базы данных, мне не приходило в голову раньше. В дополнение к решениям, представленным в комментарии, вы можете использовать явное разграничение сеанса

...