2012-06-14 12 views
6

W PerSession jak mogę uzyskać Dispose() na usługę do ognia? W kodzie poniżej Dispose() nie jest wywoływana. Ani wtedy, gdy wywołuję .Close(), ani gdy pozwalam na przekroczenie limitu czasu sesji.WCF Dispose() nie wywoływany z instancjąContectMode = PerSession

Jeśli zmienię usługę na PerCall Dispose() jest wywoływana (przy każdym wywołaniu metody). Z PerSession otrzymuję sesję (testowaną z serviceStartTime).

usługi

[ServiceBehavior (InstanceContextMode=InstanceContextMode.PerSession)] 
public class MagicEightBallService : IEightBall, IDisposable 
{ 
    private DateTime serviceStartTime; 
    public void Dispose() 
    { 
     Console.WriteLine("Eightball dispose ... " + OperationContext.Current.SessionId.ToString()); 
    } 
    public MagicEightBallService() 
    { 
     serviceStartTime = DateTime.Now; 
     Console.WriteLine("Eightball awaits your question " + OperationContext.Current.SessionId.ToString() + " " + serviceStartTime.ToLongTimeString()); 
    } 
    public string ObtainAnswerToQuestion(string userQuestion) 
    { 
     return "maybe " + OperationContext.Current.SessionId.ToString() + " " + serviceStartTime.ToLongTimeString(); 
    } 

Client

using (EightBallClient ball = new EightBallClient()) 
    {  
     while (true) 
     { 
      Console.Write("Your question: "); 
      string question = Console.ReadLine(); 
      if (string.IsNullOrEmpty(question)) break; 
      try 
      { 
       string answer = ball.ObtainAnswerToQuestion(question); 
       Console.WriteLine("8-ball says: {0}", answer); 
      } 
      catch (Exception Ex) 
      { 
       Console.WriteLine("ball.ObtainAnswerToQuestion exception " + Ex.Message); 
      }    
     } 
     ball.Close(); 
    } 

Service-Contract

[ServiceContract (SessionMode = SessionMode.Required)] 
public interface IEightBall 
{ 
    [OperationContract] 
    string ObtainAnswerToQuestion(string userQuestion); 

    [OperationContract] 
    sDoc GetSdoc(int sID); 

    DateTime CurDateTime(); 
} 

Host

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
    <system.serviceModel> 
    <bindings> 
     <wsHttpBinding> 
     <binding name="WSHttpBinding_ISampleService" 
       closeTimeout="00:01:00" openTimeout="00:01:00" 
       receiveTimeout="00:10:00" sendTimeout="00:10:00"> 
      <security mode="Message" /> 
      <reliableSession ordered="true" 
        inactivityTimeout="00:10:00" 
        enabled="true" /> 
     </binding> 
     </wsHttpBinding> 
    </bindings> 
    <services> 
     <service name="MajicEightBallServiceLib.MagicEightBallService" 
       behaviorConfiguration="EightBallServiceMEXBehavior" > 
     <endpoint address="" 
        binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_ISampleService" 
        contract="MajicEightBallServiceLib.IEightBall"> 
     </endpoint> 
     <endpoint address="mex" 
        binding ="mexHttpBinding" 
        contract="IMetadataExchange" /> 
     <host> 
      <baseAddresses> 
      <add baseAddress="http://localhost:8000/MagicEightBallService"/> 
      </baseAddresses> 
     </host>    
     </service> 
    </services> 
    <behaviors> 
     <serviceBehaviors> 
     <behavior name="EightBallServiceMEXBehavior"> 
      <serviceMetadata httpGetEnabled="true"/> 
     </behavior> 
     </serviceBehaviors> 
    </behaviors> 
    </system.serviceModel> 
</configuration> 

namespace MagicEightBallServiceHost 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Console.WriteLine("**** Console Based WCF Host *****"); 

      using (ServiceHost serviceHost = new ServiceHost(typeof(MagicEightBallService))) 
      { 
       serviceHost.Open(); 
       Console.WriteLine("The service is running"); 
       Console.ReadLine(); 
      } 
     } 
    } 
} 
+0

Czy umowa określona usługa również z 'session = true'? Myślę, że jest to jedyny sposób, w jaki klient wie, aby powiadomić serwer, gdy zakończy sesję. –

+0

@MichaelEdenfield Gdzie umieścić Session = true? Próbowałem SessionMode = SessionMode.Required, ale to nie pomogło. – Paparazzi

+0

'[ServiceContract (Session = True)]' (Nie wiem, że to jest odpowiedź, po prostu wiem, że zawsze robię to z usługami opartymi na sesjach). –

Odpowiedz

10

Dispose() metoda zostanie zwolniony. Jedynym pytaniem jest "Kiedy?".

Odpowiedź na to pytanie zależy od konfiguracji usługi.

Istnieje kilka możliwych scenariuszy:

  1. Sesja nie jest obsługiwany przez wiązanie
  2. Normalny sesję
  3. Niezawodny sesji

Dispose() jest zwolniony, gdy sesja jest zamknięta dla PerSession trybie kontekstowego. Musimy więc sprawdzić, jak długo sesja odbywa się w różnych scenariuszach.

Dla niektórych konfiguracji (na przykład domyślna BasicHttpBinding) sesja nie jest w ogóle uruchomiona. W przypadku konfiguracji bez sesji PerCall i PerSession tryby kontekstowe nie mają różnicy, a metoda Dispose zostanie wywołana bardzo szybko po wykonaniu Twojej głównej metody.

Gdy opcja Session jest włączona, można ją jawnie zamknąć przez klienta lub przez przekroczenie limitu czasu. Zwykle jest kontrolowany przez klienta. Klient inicjuje sesję przed pierwszym wywołaniem usługi i zamyka ją, gdy obiekt klienta jest zamknięty. powyżej

ServiceClient proxy = new ServiceClient(); 
Console.WriteLine(proxy.GetData(123)); 
proxy.Close(); 

proxy.Close() metoda zamyka sesję na serwerze, co z kolei wykonuje Dispose().

Zarządzanie sesjami to duży sterownik wydajności, ponieważ wymaga wykonywania dodatkowych połączeń między klientem a serwerem.

Normalnie Dispose zostanie wywołany, gdy Klient chce zamknąć sesję.

Jeśli klient nie zamknął sesji z jakiegokolwiek powodu, po pewnym czasie zostanie zamknięty przez hosta usługi. Ten okres jest kontrolowany przez właściwość Binding.ReceiveTimeout. Wartość domyślna dla tej właściwości to 10 min.

Sesja zostanie zamknięta i (Dispose() wystrzelona), jeśli nikt nie wysłał żądania do serwera z określonym identyfikatorem sesji przez 10 minut. Ten domyślny limit czasu można zmienić, ustawiając receiveTimeout na krótszą wartość w pliku web.config.

<wsHttpBinding> 
    <binding name="wsHttpEndpointBinding" receiveTimeout="00:00:05"> 
    </binding> 
</wsHttpBinding> 

ReliableSession.InactivityTimeout jest dodatkowo sprawdzany, gdy włączona jest niezawodna sesja. Jest również domyślnie ustawiony na 10 min.

Działa zgodnie z oczekiwaniami w hostowanych i usługach hostowanych przez IIS.

Spróbuj zaktualizować swój kod klienta w następujący sposób badania:

using (EightBallClient ball = new EightBallClient()) 
{  
    ball.ObtainAnswerToQuestion("test"); 
    ball.Close(); 
} 
+0

Proszę zobaczyć mój kod. Dzwonię do ball.Close(); i Dispose() nie strzela. Jeśli przerwałem sesję Dispose() nie jest wywoływana. Czy piłka.Close(); nie zamykać proxy? – Paparazzi

+0

Testowałem to przed opublikowaniem odpowiedzi. Wszystko, co powiedziałem, jest prawdziwe dla usług obsługiwanych przez IIS przy użyciu * .svc. Jak hostujesz swój kod? –

+0

Hostuję w prostej aplikacji konsolowej. Opublikuję cały host. I dzięki – Paparazzi

Powiązane problemy