Канал обратного вызова WCF становится преждевременным? - PullRequest
1 голос
/ 15 мая 2009

Мое приложение использует WCF-сервис net.tcp с каналом обратного вызова. По какой-то причине я не могу отправить обратные вызовы по событию. Вот что я делаю (весь код на стороне сервера):

При инициализации:

OperationContext Context { get; protected set; }
...
Context = OperationContext.Current;

По событию:

var callback = Context.GetCallbackChannel<IServiceCallbackContract>();
callback.SomeMethod();

Ошибка на SomeMethod() со следующим исключением: {"Cannot access a disposed object.\r\nObject name: 'System.ServiceModel.Channels.ServiceChannel'."}

Очевидно, что что-то выбрасывает канал обратного вызова, даже если клиент все еще может общаться с сервером, используя прямой (без обратного вызова) канал. Это довольно странно. К какому объекту я должен привязаться, чтобы выполнить обратный вызов? Есть ли определенный поток, в котором это должно быть запущено?

Ответы [ 5 ]

3 голосов
/ 15 мая 2009

Настройте трассировку и посмотрите, какое исключение вызывает сбой в вашем канале.

2 голосов
/ 15 мая 2009

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

1) Создайте новый класс, который будет содержать как мой запрос ввода, так и ссылку на обратный вызов, например.

public struct MyCallbackDetails {
     public MyCallbackDetails(IMyServiceCallback callback, RequestType request) : this() 
         Callback = callback;
         Request = request;
}

public IMyServiceCallback Callback { get; set; }

public RequestType request { get; set; }
}

2) Затем я запускаю отдельный поток, передающий объект MyCallbackDetails, а не просто запрос:

public ResponseType MyServiceMethod(RequestType request) {
    //...Do Some Stuff
    //Create MyCallbackDetails object to store reference to the callback and keep channel open
    MyCallDetails callDetails = new MyCallDetails(OperationContext.Current.GetCallbackChannel<IMyServiceCallback>(), request);
    //Fire off a new thread to call the BL and do some work
    Thread processThread = new Thread(RunCallbackMethod);
    processThread.Start(callDetails);
}

3) И мой RunCallbackMethod будет делать вызов BL и отвечать обратным вызовом.

void RunCallBackMethod(Object requestDetails)
{
    //Use callbackdetails to make BL calls
    MyCallbackDetails callDetails = (MyCallbackDetails)requestDetails;
    // Make BL call - all code under here is syncrhonous
    ResponseType response = BusinessLayer.BusinessMethod(callDetails.Request);
    //NB: If your responsetype is a business object you will need to convert it to a service object
    callDetails.Callback.SomeMethod(results);
}

NB. Да, я покончил с тем, что событие из моего бизнес-уровня перешло обратно в сервисный уровень, однако, поскольку я запускаю отдельный поток для бизнес-уровня, он все еще работает асинхронно и действует так же, как если бы непосредственный вызов BL в режиме ASync и ожидание события, уведомляющего о его завершении.

PS: Спасибо Рори за идею и большую часть кода для ее реализации.

0 голосов
/ 25 июня 2015

У меня была похожая проблема в моем приложении чата. Если я закрывал свое приложение и затем пытался открыть снова, я продолжал получать Cannot access a disposed object при открытии канала.

Прослеживая приложение, я сделал следующее, чтобы устранить основную причину.

  • Установите точку останова в клиентском приложении, когда я делаю последний звонок в сервис (выход из системы) перед закрытием. - Здесь нечего сообщать.
  • Remote Отладка службы на сервере методом выхода из системы. - Заметил, что обратный вызов не будет работать и сгенерировал исключение, потому что канал был по какой-то причине удален.
  • Проверены атрибуты для OperationContract - обнаружена проблема!

Проблема была в том, и эксперты WCF меня поправили, если я ошибаюсь, что OperationContract был похож на

[OperationContract(IsInitiating = false, IsTerminating = true)]
bool RemoveUser(Client user);  

Установка IsTerminating = true означала, что канал был закрыт до того, как служба обработала метод выхода из системы, и поэтому, когда он попытался отозвать его, он не смог.

Установка IsTerminating = false и закрытие канала на стороне клиента решили проблему для меня.

В моем приложении обратный вызов даже не должен происходить, но это отдельная проблема, все вместе и не связанные. Суть в том, что если у вас есть IsTerminating = True в операции, убедитесь, что вы не используете обратный вызов.

0 голосов
/ 16 мая 2009

Проблема была решена как моя ошибка. Обратные вызовы работали как задумано, за исключением некоторых устаревших, которые при вызове создавали исключения. Так как я не пытался / ловил их, целое событие ломалось от этих устаревших обратных вызовов: (.

Спасибо всем, кто пытался ответить на мой вопрос.

0 голосов
/ 15 мая 2009

Вы пытались использовать OperationContext.Current напрямую вместо переменной экземпляра Context?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...