在GetCallbackChannel

时间:2019-06-27 19:11:34

标签: c# wcf

我正在使用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的地步,所以我要执行以下操作:

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()

作为参考,我在摘录了WCF found here的Duplex Services上的MSDN文章之后,创建了此文件。我的google-fu只打开了链接,说的链接像是“包括将第二个合同作为CallbackContract包含在内”,我想我已经在这样做了。

欢迎任何建议,包括可能的替代方法。一个限制是,因为客户端应用程序必须以普通用户身份运行(而不是管理员/提升权限),所以我不能简单地做两个单独的管道,一个由服务托管,另一个由客户端托管,因为WCF安全限制将使客户端成为管道对其他进程不可见。

1 个答案:

答案 0 :(得分:0)

找到了我自己问题的答案。

本质上,我的问题是我没有在其生命周期的正确点保存回调对象。

查看提供的示例,所有回调均用作对入站服务调用的响应/答复。就我而言,这就是我要在SendMessage()中获取它的原因。

再看一些示例,我发现了一个适用于发布者/订阅者设计模式here的示例。关键区别在于,它将在调用一个方法(在这种情况下为Subscribe)期间保存回调对象,并在其他地方使用它。

以下相关代码示例:

stdClass Object
(
    [Colors] => Array
        (
            [0] => stdClass Object
                (
                    [value] => Blue
                )

        )

    [Sizes] => Array
        (
            [0] => stdClass Object
                (
                    [value] => 10
                )
            [1] => stdClass Object
                (
                    [value] => 30

                )

        )

)

因此,在我的特定情况下,我期望的行为/解决方案比呼叫和响应模式更接近发布/订阅模式。因此,我只需要添加一个额外的服务方法Register()即可保存回调对象,并让客户端在建立连接通道后调用该服务方法。