我正在使用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安全限制将使客户端成为管道对其他进程不可见。
答案 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()即可保存回调对象,并让客户端在建立连接通道后调用该服务方法。