WCF 服务主机回调不稳定



>问题

最可重现的方案是从托盘应用程序上的链接启动桌面应用程序,然后通过回调请求桌面应用程序执行某些操作。这实际上总是会引发超时错误,就像其他后续错误一样。

WCF 环境:

服务器:系统托盘小程序

客户端:WinForms桌面应用程序

资源:

  • WCF 进程间通信
  • 异步双向 WCF 通信
  • 执行 WCF 实例管理的三种方法
  • 别人

从托盘启动桌面应用程序的方法

// 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 ...MyAppTrayCustomApplicationContext.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 ...MyAppTrayCommunicationIpcFromTray.cs:line 142

至于我的代码,它基本上看起来像更改了类名的 WCF 进程间通信示例,但在其他方面相似,因此无需放置在此处。

我正在尝试在失败后重新启动,但.Close()后跟.Open()并不总是有效,就像可能被释放的那样,创建一个新的会得到一个已经存在的 URI 端点。我尝试了很多方法让事情稳定,但无济于事。

我现在有 10 秒的时间。最初的超时时间为 1 分钟,默认值为 Microsoft。起初我以为我的申请挂了。会话内容无助于事业。我尝试添加延迟,Thread.Sleep(4000(,但这很烦人,什么也没做。应用程序可能已打开,但同样,睡眠 4000 或

4000000000000 没有任何区别。最重要的是,无论出于何种原因,我都无法稳定回调。是的,回调是静态的。除了这一点,我看不到任何其他方法。

思潮?我现在非常沮丧。

我的代码有两个问题,我在这里发布给后代。

  1. 延迟/DOS

主要问题是因为我的回调彼此太近(不是一两个(。我在调试时注意到故障在我的do-while循环中。我跟踪了循环内的迭代次数,以查找要更改的应用程序状态,并注意到计数器位于 1,而不是 0。这让我意识到我需要延迟。我首先将呼叫之间的延迟设置为 25 毫秒,但仍然有问题。然后我尝试了50ms,这解决了问题。

我不得不在几次不同的调用后添加 3 秒的延迟,以使链接不会出错。我正在阅读一些,这是设计使然。据我所知,Microsoft在 WCF 中有一个 DOS(拒绝服务(方案。我可能遇到了这个问题,或者只是需要一点清理时间让频道在另一个调用之前重置,尽管该论点并不能解释更长的参数。

  1. 应用关闭时关闭频道

    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 的基本框架,但问题在于生产代码的细节。

最新更新