2012-06-14 2 views
6

В PerSession, как мне получить Dispose() в службе для запуска? В коде ниже Dispose() не вызывается. Ни когда я вызываю .Close(), ни когда я позволяю сеансу тайм-аута.WCF Dispose() не вызывается с InstanceContectMode = PerSession

Если я меняю службу на PerCall Dispose() вызывается (при каждом вызове метода). С PerSession я получаю сеанс (тестируется с помощью serviceStartTime).

Сервис

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

Сервис-Контракт

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

    [OperationContract] 
    sDoc GetSdoc(int sID); 

    DateTime CurDateTime(); 
} 

Хост

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

Ваш контракт на обслуживание, также указанный с 'Session = true'? Я думаю, что это единственный способ, которым клиент знает сервер, когда это делается с сеансом. –

+0

@MichaelEdenfield Где бы я поставил Session = true? Я пробовал SessionMode = SessionMode.Required, но это не помогло. – Paparazzi

+0

'[ServiceContract (Session = True)]' (Я не знаю, что это был ответ, который я просто знаю, я всегда делаю это с помощью своих служб на основе сеанса.) –

ответ

10

Dispose() метод будет уволен. Вопрос только в том, «Когда?».

Ответ на этот вопрос зависит от конфигурации службы.

Есть несколько возможных сценариев:

  1. Session не поддерживается путем связывания
  2. обычного сеанса
  3. Расписание сессии

Dispose() срабатывает, когда сессия закрыта для PerSession режима контекста. Поэтому нам нужно проверить, сколько сеансов работает в разных сценариях.

Для некоторых конфигураций (например, по умолчанию BasicHttpBinding) сеанс вообще не запускается. В случае конфигурации без сеанса PerCall и PerSession контекстные режимы не имеют разницы, а метод Dispose будет называться очень скоро после выполнения вашего основного метода.

Когда Session включен, он может быть закрыт явно клиентом или таймаутом. Обычно он контролируется клиентом. Клиент инициирует сеанс перед первым вызовом службы и закрывает его, когда объект клиента закрыт.

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

proxy.Close() выше метод закрывает сессию в сервере, что, в свою очередь выполняет Dispose().

Управление сеансами - это большой драйвер производительности, поскольку для его выполнения требуются дополнительные вызовы между клиентом и сервером.

Как обычно, Dispose будет вызываться, когда Клиент хочет закрыть сеанс.

Если клиент не закрыл сеанс по какой-либо причине, он будет закрыт хостом службы через определенный промежуток времени. Этот период контролируется недвижимостью Binding.ReceiveTimeout. Значение по умолчанию для этого объекта составляет 10 мин.

Сессия будет закрыта и (Dispose() уволен), если никто не отправил запрос на сервер с определенным идентификатором сеанса в течение 10 минут. Этот таймаут по умолчанию можно изменить, установив receiveTimeout на некоторое более короткое значение в web.config.

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

ReliableSession.InactivityTimeout дополнительно проверяется при Расписание сессии включен. Он также по умолчанию считается 10 мин.

Работает так, как ожидалось, в самообслуживании и службах, поддерживающих IIS.

Попробуйте обновить код клиента следующим образом тесту:

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

См. Мой код. Я вызываю ball.Close(); и Dispose() не срабатывает. Если я отпущу сессию, Dispose() не вызывается. Is ball.Close(); не закрывая прокси? – Paparazzi

+0

Я протестировал это, прежде чем отправлять ответ. Все, что я сказал, верно для службы, обслуживаемой IIS, с использованием * .svc. Как вы размещаете свой код? –

+0

Я хостинг в простом консольном приложении. Я отправлю весь хост. ANd спасибо – Paparazzi

Смежные вопросы