我正在设计一个带回调的WCF服务,但我的回调函数的实现永远不会被调用。我对生成的服务代理感到困惑,所以请帮忙。
以下是场景:在服务器端,我定义了服务接口IMyService和回调接口IMyServiceCallback,我还在服务器项目中实现了IMyService。除了服务器项目,我肯定有另一个客户端项目,我在VS中添加了服务引用。我在客户端实现了IMyServiceCallback接口。所以这就出现了问题:当我调试它时,函数永远不会进入我的IMyServiceCallback实现,当然所需的结果永远不会出现。
这就是我困惑的地方:当我在客户端添加服务引用时,它实际上在本地生成了三个接口:IMyService,IMyServiceCallback和IMyServiceChannel以及客户端代理类。在我的本地IMyServiceCallback实现中,我声明该类实现了本地IMyServiceCallback接口,而不是服务端的接口。这可能是问题吗?为什么在不同项目下有两个接口声明(因此不同的命名空间)?我实现客户端接口的原因是,如果我从服务器端接口实现,它会给出错误:“当我尝试调用服务时,提供给ChannelFactory的InstanceContext包含一个不实现CallbackContractType错误的UserObject”。另一个令人困惑的部分是,在服务器端,如果我将回调接口名称声明为IMyCallback,或者其他任何东西,而不是IMyServiceCallback,客户端上生成的接口仍然是IMyServiceCallback,这是服务接口的名称加上后缀“回调”。在这种情况下,我还得到“提供给ChannelFactory的InstanceContext包含一个不实现CallbackContractType错误的UserObject”。
我想有些东西我误解了“添加服务引用”以及我应该如何实现接口(实现哪一个)。谁能帮助我?谢谢!
更新:
我以某种方式解决了这个问题。首先,两个声明是好的。本地客户端需要实现添加服务引用时生成的本地接口。我的问题是我还定义了一个DataContract,但生成的参考文件没有它。它可能是因为我已经添加了服务项目的程序集作为参考(有人说在这种情况下添加服务引用不会生成Datacontract)或因为我缺少DataMember属性。但无论如何,在我修复了两个部分后,该功能现在正在运行。
答案 0 :(得分:2)
当您“添加服务引用”并生成代理时,它与您的服务实现完全分开。请记住,您可能正在使用尚未编写且无法访问服务源代码的服务。
客户端代码应使用客户端生成的接口。如果您更改了服务,则需要重新生成代理。
如果您发现这太混乱,并且您知道您将始终控制两端,则可以在公共程序集中共享服务接口,并使用DuplexChannelFactory.CreateChannel()
在运行时生成代理类。
至于你的问题,我只能假设你没有正确注册你的回调。这包括here。
答案 1 :(得分:0)
如果要发布,则必须在同一项目中一起实现IMyServiceCallback和IMyService。 如果只订阅,则必须实现IMyServiceCallback接口
答案 2 :(得分:0)
当我的回调指令嵌入到函数调用中时,我解决了这个问题。 我了解到将回调放在一个不返回结果的方法中工作正常。 但是,当回调指令放在函数中时,我遇到了超时问题。
我通过在被调用函数中使用backgroundworker线程来解决它:
public static IMyServiceCallback Callback;
.
.
.
TaskStateData taskStateData = GetSomeData();
BackgroundWorker backgroundWorker = new BackgroundWorker();
backgroundWorker.DoWork += (se, ev) =>
{
Tuple<OperationContext, TaskStateData> data = ev.Argument as Tuple<OperationContext, TaskStateData>;
var operationContext = data.Item1;
if (operationContext != null)
{
Callback = operationContext.GetCallbackChannel<IMyServiceCallback>();
Callback.OnCallBack();
}
};
Tuple<OperationContext, TaskStateData> payload = new Tuple<OperationContext, TaskStateData>(OperationContext.Current, taskStateData);
backgroundWorker.RunWorkerAsync(payload);