【发布时间】:2015-03-03 16:57:09
【问题描述】:
我有以下服务和回调合同(删节):
服务合同:
[ServiceContract(CallbackContract = typeof(ISchedulerServiceCallback))]
public interface ISchedulerService
{
[OperationContract]
void Stop();
[OperationContract]
void SubscribeStatusUpdate();
}
回调合约:
public interface ISchedulerServiceCallback
{
[OperationContract(IsOneWay = true)]
void StatusUpdate(SchedulerStatus status);
}
服务实施:
[CallbackBehavior(UseSynchronizationContext = false, ConcurrencyMode = ConcurrencyMode.Multiple)] // Tried Reentrant as well.
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] // Single due to a timer in the service that must keep time across calls.
public class SchedulerService : ISchedulerService
{
private static Action<SchedulerStatus> statusUpdate = delegate { };
public void Stop()
{
Status = SchedulerStatus.Stopped;
statusUpdate(Status);
}
private SchedulerStatus Status { get; set; }
public void SubscribeStatusUpdate()
{
ISchedulerServiceCallback sub = OperationContext.Current.GetCallbackChannel<ISchedulerServiceCallback>();
statusUpdate += sub.StatusUpdate;
}
}
服务消费者:
public class SchedulerViewModel : ViewModelBase, ISchedulerServiceCallback
{
private SchedulerServiceClient proxy;
public SchedulerViewModel()
{
StopScheduler = new DelegateCommand(ExecuteStopSchedulerCommand, CanExecuteStopSchedulerCommand);
}
public void SubScribeStatusCallback()
{
ISchedulerServiceCallback call = this;
InstanceContext ctx = new InstanceContext(call);
proxy = new SchedulerServiceClient(ctx);
proxy.SubscribeStatusUpdate();
}
private SchedulerStatus _status;
private SchedulerStatus Status
{
get
{
return _status;
}
set
{
_status = value;
OnPropertyChanged();
}
}
public void StatusUpdate(SchedulerStatus newStatus)
{
Status = newStatus;
Console.WriteLine("Status: " + newStatus);
}
public DelegateCommand StopScheduler { get; private set; }
bool CanExecuteStopSchedulerCommand()
{
return true;
}
public void ExecuteStopSchedulerCommand()
{
proxy.Stop();
}
}
SchedulerViewModel 通过其Status 和StopScheduler 属性绑定到一个带有文本框和按钮的简单窗口。 WCF 由一个简单的 Console 应用托管,用于调试:解决方案设置为先启动服务主机(控制台应用),然后再启动 WCF 应用。
当我单击主应用程序窗口上的按钮时,我希望调用该命令,即调用proxy.Stop();。这应该改变服务状态的状态并调用回调。我认为确实如此,但回调超时。调试器挂在proxy.Stop();线上,最终得到错误信息:
这个请求操作发送到 http://localhost:8089/TestService/SchedulerService/ 没有收到 在配置的超时 (00:00:59.9990000) 内回复。时间 分配给该操作的可能是较长时间的一部分 超时。这可能是因为服务仍在处理 操作或因为服务无法发送回复消息。 请考虑增加操作超时(通过强制转换 通道/代理到 IContextChannel 并设置 OperationTimeout 属性)并确保服务能够连接到 客户。
当我在控制台应用程序中使用SchedulerViewModel 时,回调工作正常,并且视图模型在控制台窗口中打印Status: Stopped。一旦我涉及其他线程,回调就不再起作用。
其他线程是 viewmodel 提升 OnPropertyChanged 以更新绑定的文本框,我不知道是否有更多线程参与启用/禁用命令。
调用的服务方法中的任何时间都不应超过毫秒,我相信我正朝着正确的方向前进,相信这是一个线程和/或 UI 挂起问题,因为我在进行研究时看到了类似的问题。大多数是完全不同的场景和深入的技术解决方案。
为什么会发生这种情况,我有什么办法可以使用相当标准的 WPF 和 WCF 基础结构和函数来启用此回调?我可悲的替代方案是让服务将状态写入文件,并让视图模型观察文件。这是一个肮脏的解决方法?
【问题讨论】:
标签: .net wpf wcf events wcf-callbacks