2011-09-03 8 views
9

WCF 세션을 유지 관리하는 서비스를 만들어야합니다. 생성자에서 DB로부터 데이터를 읽었습니다. 세션이 끝나면 다시 저장해야합니다.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(); 
    } 
+0

이것은 무엇보다도 완전히 잘못된 서비스 디자인입니다. –

답변

16

docs

홍보에서 ogrammer는 가비지 수집기에 의해 결정되기 때문에 소멸자가 이라고 불리는시기를 제어 할 수 없습니다. 가비지 수집기가 응용 프로그램에서 더 이상 사용하지 않는 개체를 확인합니다. 파괴 대상 객체를 고려하면 은 소멸자 (있는 경우)를 호출하고 객체를 저장하는 데 사용 된 메모리를 회수합니다. 소멸자는 프로그램이 종료 될 때도 호출됩니다.

구현에 문제가 있습니다. 소멸자를 사용하여 데이터를 지속시킵니다. 소멸자를 결정 론적으로 호출 할 수 없기 때문에 소멸자가 별도의 종료 대기열에서 처리되므로 이는 잘못된 것입니다. 즉, 객체를 파괴했지만 소멸자가 즉시 호출되지 않을 수도 있습니다.


가 소멸자를 제거하고 대신으로 IDisposable 패턴을 사용하여 해결하는 방법, 폐기에 논리를 저장했습니다. 세션이 종료되면, WCF는 IDisposable.Dispose

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

편집
Pls는 호출이 답변에 코멘트를 볼 수 있습니다. 사실 IDisposable이 데이터베이스 커밋을위한 적절한 장소가 아니라는 사실에 동의합니다. 당신이 사용할 수있는 의견에 제공된 솔루션에 덧붙여 explicit session demarcation

+16

아니요! "IDisposable.Dispose"에 넣지 마십시오! 'IDisposable.Dispose'는 관리 자원을 정리하기위한 것입니다. 데이터베이스에 저장하는 것은 관리 자원을 정리하는 것이 아닙니다. 이것은이 인터페이스의 * accepted * 및 * expected * 사용에 반대합니다. 'SetName'을 데이터베이스에 변경 사항을 커밋하거나 서비스'Commit'에 다른 메소드를 제공하십시오. 또한, C#에서 우리는 그것을 "파이널 라이저"라고 부릅니다. 예,이 주제가 혼란 스럽습니다. – jason

관련 문제