none
WCF: ПРОБЛЕМА с callback: Cannot access a disposed object. Object name: 'System.ServiceModel.Channels.ServiceChannel'. RRS feed

  • Вопрос

  • WCF хостится в WinFormApp. Все работало нормально, но когда идет обращение к методу - форма на время выполнения подвисает - значит нужно отправить её в отдельный поток. Решил реализовать для начала с BackgroundWorker. Вот примерный код:

     

    [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Single, InstanceContextMode = InstanceContextMode.Single)]
    public
     class
     TDService : ITDServiceInventory
     {
      private
     static
     List<ITDServiceInventoryCallback> _callbackList = new
     List<ITDServiceInventoryCallback>();
      private
     static
     Database Db = null
    ;
      private
     BackgroundWorker bw;
    
      static
     TDService()
      {
       Db = new
     Database(System.Configuration.ConfigurationManager.AppSettings["Db"
    ]);
       Db.Open();
      }
    
      private
     void
     bw_DoWork(object
     sender, DoWorkEventArgs e)
      {
       try
    
       {
        // какой-то свой класс
    
        WorkInfo workInfo = (WorkInfo)e.Argument;
        ...
        if
     (((ICommunicationObject)_callbackList[workInfo.CallBackIndex]).State == CommunicationState.Opened)
         lock
     (_callbackList)
         {
          _callbackList[workInfo.CallBackIndex].SomeMethod(workInfo.Args);
          _callbackList.RemoveAt(workInfo.CallBackIndex);
         }
        }
       }
       catch
     (Exception ex)
       {
        
       }
      }
    
      public
     void
     Method1()
      {
       try
    
       {
        ITDServiceInventoryCallback callback = OperationContext.Current.GetCallbackChannel<ITDServiceInventoryCallback>();
        
        if
     (!_callbackList.Contains(callback))
         _callbackList.Add(callback);
    
        WorkInfo workInfo = new
     WorkInfo(.., _callbackList.IndexOf(callback));
    
        bw = new
     BackgroundWorker();
        bw.WorkerReportsProgress = false
    ;
        bw.WorkerSupportsCancellation = false
    ;
        bw.DoWork += new
     DoWorkEventHandler(bw_DoWork);
        bw.RunWorkerAsync(workInfo);<br/>
       }
       catch
     (Exception ex) 
       {
        ...
       };
      }
      }
    
    
    // ITDServiceInventory.cs
    
    [ServiceContract(Name = "TDService"
    , 
      Namespace = "..."
    , 
      SessionMode = SessionMode.Required, 
      CallbackContract = typeof
    (ITDServiceInventoryCallback))]
     public
     interface
     ITDServiceInventory
     {
      [OperationContract(IsOneWay = true
    )]
      void
     Method1();
     }
    
    // ITDServiceInventoryCallback.cs
    
     public
     interface
     ITDServiceInventoryCallback
     {
      [OperationContract(IsOneWay = true
    )] 
      void
     SomeMethod(object
     obj);
     }
    
    

     

    если без создания BackgroundWorker и передачи туда индекса callback - все работает нормально. С BackgroundWorker получаю ошибку

    Cannot access a disposed object.
    Object name: 'System.ServiceModel.Channels.ServiceChannel'.
    mscorlib

    Server stack trace:
       at System.ServiceModel.Channels.CommunicationObject.ThrowIfDisposedOrNotOpen()
       at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
       at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs)
       at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
       at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

    Exception rethrown at [0]:
       at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
       at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)

     

    в строке

     

    _callbackList[workInfo.CallBackIndex].SomeMethod(workInfo.Args);

     

    Почему канал закрывается после выхода из Method1()?

     

    20 января 2011 г. 14:43

Ответы

  • Как же я ступил - совсем не там искал ошибку. Я просто закрыл канал в клиенте, после вызова метода. Copy/Paste bug. Конечно же после закрытия канала/соединения получил вполне логичный exception.

    Спасибо в любом случае!!!

    • Предложено в качестве ответа PashaPash 20 января 2011 г. 19:53
    • Помечено в качестве ответа Abolmasov Dmitry 21 января 2011 г. 6:17
    20 января 2011 г. 19:46

Все ответы

  • А почему не должен? OperationContext, и все, что из него получено, валидно только на время операции. После завершения Method1 канал к клиенту закрывается - иначе он бы висел открытым вечно.
    My blog
    20 января 2011 г. 15:28
  • А почему не должен? OperationContext, и все, что из него получено, валидно только на время операции. После завершения Method1 канал к клиенту закрывается - иначе он бы висел открытым вечно.
    My blog


    есть

    private 
    static
     List<ITDServiceInventoryCallback> _callbackList = new
     List<ITDServiceInventoryCallback>();

    и я делаю

    _callbackList.Add(callback);

    Я недавно только начал изучать WCF. Написал другое приложение, где подобная модель работает. То есть клиент вызывает какой-то метод, берется его callback, добавляется в callbackList. Далее если происходит другое событие, другой клиент соединяется с сервисом, и сервис, по некоторым условиям оповещает существующих в callbacklist клиентов. Это дуплексные операции, насколько я понимаю (т.е. канал должен быть открытым столько, сколько указано в настройках).


    20 января 2011 г. 15:34
  • Дуплексная операция (точнее, поддержка Callback) означает что во время выполнения операции на сервере код сервера может вызвать callback-операцию на клиенте. Операция на сервере - это Method1. 

    В настройках указаны таймауты - максимальное время, по истечению которого канал будет принудительно закрыт. Например, если Method1 задумается на час, то тамаут в 5 минут не даст системе зря держать открытым канал. 


    My blog
    20 января 2011 г. 15:45
  • Дуплексная операция (точнее, поддержка Callback) означает что во время выполнения операции на сервере код сервера может вызвать callback-операцию на клиенте. Операция на сервере - это Method1. 

    В настройках указаны таймауты - максимальное время, по истечению которого канал будет принудительно закрыт. Например, если Method1 задумается на час, то тамаут в 5 минут не даст системе зря держать открытым канал. 


    My blog


    у меня в другом проекте есть 

    [OperationContract()]
    string Login(string Username, string Password);
    

    после того как метод отработает, его CallbackChannel остается в статическом объекте на сервере. В клиенте настроены большие таймауты и канал открыт почти всегда. Я не получаю такого exception, спокойно имею доступ к callback'у. Покопаюсь-ка я в config'ах.

    PashaPash спасибо. Если есть еще мысли, было бы неплохо.

    20 января 2011 г. 19:35
  • Как же я ступил - совсем не там искал ошибку. Я просто закрыл канал в клиенте, после вызова метода. Copy/Paste bug. Конечно же после закрытия канала/соединения получил вполне логичный exception.

    Спасибо в любом случае!!!

    • Предложено в качестве ответа PashaPash 20 января 2011 г. 19:53
    • Помечено в качестве ответа Abolmasov Dmitry 21 января 2011 г. 6:17
    20 января 2011 г. 19:46