问题
最可重现的方案是从托盘应用程序上的链接启动桌面应用程序,然后通过回调请求桌面应用程序执行某些操作。这实际上总是抛出超时错误作为其他后续错误。
WCF环境:
服务器:系统托盘小程序
客户端:WinForms桌面应用程序
资源:
从托盘启动桌面应用程序的方法
// Start the process.
ProcessStartInfo oProcessInfo = new ProcessStartInfo()
{
FileName = regValue.ToString(),
WindowStyle = ProcessWindowStyle.Normal,
UseShellExecute = true,
CreateNoWindow = false,
};
Process oProcess = new Process()
{
StartInfo = oProcessInfo,
};
oProcess.Start();
我打几次电话,但第一次通话时互动不一定会失败。这是一个示例调用:
var callback = IpcToTray.Callback;
if (null == callback)
return 0;
UInt16 idIsLaunched = callback.IsAppLaunched();
if (Id_AppIsLaunched == idIsLaunched)
return true;
我目前正在使用PerCall,但使用的是PerSession。两者都无济于事。
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class IpcToTray : IIpcToTray
{
}
以下是一些错误:
System.TimeoutException
HResult=0x80131505
Message=This request operation sent to http://schemas.microsoft.com/2005/12/ServiceModel/Addressing/Anonymous did not receive a reply within the configured timeout (00:00:10). The time allotted to this operation may have been a portion of a longer timeout. This may be because the service is still processing the operation or because the service was unable to send a reply message. Please consider increasing the operation timeout (by casting the channel/proxy to IContextChannel and setting the OperationTimeout property) and ensure that the service is able to connect to the client.
Source=mscorlib
StackTrace:
at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
at MyAppIpc.IIpcCallbackToTray.GetMyAppMode()
at MyAppTray.Communication.IpcFromTray.GetMyAppMode() in ...\IpcFromTray.cs:line 194
System.ObjectDisposedException
HResult=0x80131622
Message=Cannot access a disposed object.
Object name: 'System.ServiceModel.ServiceHost'.
Source=System.ServiceModel
StackTrace:
at System.ServiceModel.Channels.CommunicationObject.ThrowIfDisposedOrImmutable()
at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Open()
at MyAppTray.CustomApplicationContext.StartPipeServer() in ...\MyAppTray\CustomApplicationContext.cs:line 105
System.ServiceModel.CommunicationObjectAbortedException
HResult=0x80131501
Message=The operation 'IsAppLaunched' could not be completed because the sessionful channel timed out waiting to receive a message. To increase the timeout, either set the receiveTimeout property on the binding in your configuration file, or set the ReceiveTimeout property on the Binding directly.
Source=mscorlib
StackTrace:
at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
at MyAppIpc.IIpcCallbackToTray.IsAppLaunched()
at MyAppTray.Communication.IpcFromTray.IsAppLaunched() in ...\MyAppTray\Communication\IpcFromTray.cs:line 142
至于我的代码,它基本上看起来像WCF进程间通信示例,具有更改的类名,但在其他方面类似,所以不需要放在这里。
我试图在失败后重新启动,但.Close()
后跟.Open()
并不总是有效,因为可能会处理,创建一个新的获取URI端点已经存在。我尝试了许多方法让事情变得稳定无济于事。
我现在有时间到10秒钟。原始超时为1分钟,默认为Microsoft。我认为我的申请一开始就挂了。会话内容无助于原因。我尝试添加一个延迟,Thread.Sleep(4000),但这很烦人,什么都不做。该应用程序可能是开放的,但是,再次,睡眠4000或4000000000000没有任何区别。
最重要的是,无论出于何种原因,我都无法稳定回调。是的,回调是静态的。除此之外,我没有看到任何其他方式。
思考?我此刻感到非常沮丧。
我的代码有两个问题,我在这里发布后代。
主要问题是因为我使回调过于接近(不是一两个)。我注意到,在调试失败是在我的do-while
循环中。我一直在跟踪循环内部的迭代次数,寻找应用程序的状态进行更改,并注意到计数器为1,而不是0.这让我意识到我需要延迟。我将呼叫之间的延迟设置为25ms仍然存在问题。然后我尝试了50ms,解决了这个问题。
我必须在几次不同的呼叫之后添加一个3秒的延迟,以便链路不会出错。我正在读一点,这是设计的。微软在WCF中有一个DOS(拒绝服务)方案,我理解的最好。有可能我遇到了这个或者只是需要一些清理时间让通道在另一个调用之前重置,尽管那个参数不能解释更长的一个。
this.HostIpcToTray.CloseCallback();
this.IpcPipeFactory.Close();
private void IpcPipeFactory_Closing(object sender, EventArgs e)
{
this.IsConnectedPipeToTray = false;
this.HostIpcToTray = null;
this.IpcPipeFactory.Closing -= IpcPipeFactory_Closing;
}
第一个调用,将静态Callback变量设置为null,以便服务在下次应用程序启动之前不能使用已处置的对象。
我不得不取消订阅Closing
事件,我在Closing
事件中做了这件事。
我调用Close()通道,我没有这样做。我猜垃圾收集不能正确关闭频道。我注意到了这个问题,当我试图关闭主应用程序,客户端,然后再次启动应用程序并使用托盘进行通信时我发生了故障。一些研究导致了上面的代码。
许多示例显示了WCF IPC的基本框架,但是恶魔是生产代码的详细信息。