Получение InvalidCastException на GetCallbackChannel - PullRequest
0 голосов
/ 27 июня 2019

Я использую WCF для двусторонней связи.Намерение состоит в том, чтобы иметь возможность отправлять сообщения назад и вперед между клиентским приложением и службой Windows.Связь с клиентским приложением работает нормально, но попытка использовать канал обратного вызова для связи от службы обратно к клиенту завершается неудачно с InvalidCastException всякий раз, когда я пытаюсь получить службу обратного вызова.

Контракты на обслуживание:

[ServiceContract(CallbackContract=typeof(IPipeListenerCallbackService), SessionMode=SessionMode.Required)]
public interface IPipeListenerService
{
    [OperationContract(IsOneWay=true)]
    void SendMessage(string message);
}

[ServiceContract]
public interface IPipeListenerCallbackService
{
    [OperationContract(IsOneWay=true)]
    void SendMessage(string message);
}

Реализация:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class PipeListenerService : IPipeListenerService
{
    public void SendMessage(string message)
    {
        //do something...
    }


    public IPipeListenerCallbackService Callback
    {
        get
        {
            return OperationContext.Current.GetCallbackChannel<IPipeListenerCallbackService>();
        }
    }

}

Сервисный код для размещения / открытия WCF ServiceHost:

try
{
    PipeListenerService service = new PipeListenerService();
    Uri pipeLocation = new Uri("net.pipe://localhost/" + this.PipeName);

    this.pipeServiceHost = new ServiceHost(service, pipeLocation);
    NetNamedPipeBinding binding = new NetNamedPipeBinding();
    this.pipeServiceHost.AddServiceEndpoint(typeof(IPipeListenerService), binding, "MessagePipe");

    this.pipeServiceHost.Open();                
}
catch (Exception ex)
{
    //do proper error handling here                
}

В другом месте в сервисном коде я добираюсь до точки, где я хочучтобы фактически вызвать SendMessage для Callback, поэтому я делаю следующее:

PipeListenerService theService = this.pipeServiceHost.SingletonInstance as PipeListenerService;
if (theService != null)
{
   theService.Callback.SendMessage(message);
}

Исключение выдается в точке, где оно получает свойство Callback.

Исключение:

System.InvalidCastException: Невозможно привести объект типа 'System.ServiceModel.Channels.ServiceChannel' к типу 'CommUtil.IPipeListenerCallbackService'.в System.ServiceModel.OperationContext.GetCallbackChannelT в .PipeListenerService.get_Callback ()

Для справки, я создал это после переваривания статей MSDN по дуплексным службам для WCF , найденных здесь .Мой гугл-фу только включил ссылки, которые говорили как «Включить второй контракт как CallbackContract», что, я думаю, я уже делаю.

Любые предложения приветствуются, включая возможные альтернативные подходы.Одно ограничение состоит в том, что, поскольку клиентское приложение должно запускаться как обычный пользователь (не администратор / повышенный уровень), я не могу просто сделать 2 отдельных канала, один размещается службой, а другой - клиентом, так как ограничения безопасности WCF сделают клиентатруба не видна другим процессам.

1 Ответ

0 голосов
/ 10 июля 2019

Нашел ответ на свой вопрос.

По сути, моя проблема заключалась в том, что я не сохранял объект обратного вызова в правильной точке его времени жизни.

Глядя на предоставленные образцы, все обратные вызовы были использованы в качестве ответа / ответа на входящий сервисный вызов. В моем случае это было бы, если бы я взял его в SendMessage ().

Глядя на еще несколько образцов, я нашел один для шаблона проектирования издателя / подписчика здесь . Основное отличие состоит в том, что он будет сохранять объект обратного вызова во время вызова одного метода (в данном случае Subscribe) и использовать его в другом месте.

Соответствующие примеры кода ниже:

public void Subscribe()  
    {  
        callback = OperationContext.Current.GetCallbackChannel<ISampleClientContract>();  
        priceChangeHandler = new PriceChangeEventHandler(PriceChangeHandler);  
        PriceChangeEvent += priceChangeHandler;  
    }  

public void PriceChangeHandler(object sender, PriceChangeEventArgs e)  
    {  
        callback.PriceChange(e.Item, e.Price, e.Change);  
    }  

Итак, в моем конкретном случае мое желаемое поведение / решение ближе к шаблону pub / sub, чем к шаблону вызова и ответа. Поэтому мне просто нужно было добавить дополнительный сервисный метод Register (), который бы сохранял объект обратного вызова, и чтобы клиент вызывал этот сервисный метод после установления канала соединения.

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