我有以下情况:
我的主应用程序(APP1)启动进程(SERVER1)。 SERVER1通过命名管道承载WCF服务。我想连接到这个服务(从APP1),但有时它还没有准备好。
我创建了ChannelFactory,打开它并让它生成一个客户端。如果我现在在生成的客户端上调用一个方法,我会收到一个错误,告诉我没有找到Enpoint:
var factory = new ChannelFactory<T>(new NetNamedPipeBinding(), new EndpointAddress("net.pipe//localhost/myservice");
factory.Open()
var Client = factory.CreateChannel();
Client.Foo();
如果我在拨打服务之前稍等一下,一切都很好;
var Client = factory.CreateChannel();
Thread.Sleep(2000);
Client.Foo();
如何确保服务准备就绪而无需等待一段时间?
答案 0 :(得分:6)
如果一般情况是您只是在等待其他服务启动,那么您也可以使用在您的界面上执行“Ping”方法的方法,该方法不执行任何操作,并在重新开始响应之前重试。
我们做了类似的事情:我们尝试在启动时在循环中调用ping方法(重试之间为1秒),在我们的日志中记录(但最终忽略)尝试访问我们的服务时发生的任何TargetInvocationException
。一旦我们得到第一个正确的答案,我们继续进行。
当然,这仅涵盖启动预热案例 - 成功ping后服务可能会停止,或者我们可能因“服务未就绪”之外的原因而获得TargetInvocationException
。
答案 1 :(得分:5)
一旦服务主机完全打开并且通道监听器的Opened事件被触发,您可以使服务信号成为事件[编辑 - 请参阅注释]。应用程序将在使用其代理之前等待事件。
注意:使用命名事件很简单,因为.NET类型EventWaitHandle
为您提供了所需的一切。使用匿名事件是可取的,但需要更多工作,因为.NET事件包装器类型不会为您提供可继承的事件句柄。但是,如果您自己P / Invoke Windows DuplicateHandle
API以获取可继承的句柄,然后在其命令行参数中将重复的句柄值传递给子进程,则仍然可以。
答案 2 :(得分:2)
如果您使用的是.Net 4.0,则可以使用WS-Discovery使服务通过广播IP宣布其存在。
该服务还可以将消息发送到队列(MSMQ绑定),其寿命很短,比如几秒钟,客户端可以监控。
让服务创建一个信号文件,然后在客户端使用FileSystemWatcher来检测它何时被创建。
只需while (!alive) try { alive = client.IsAlive(); } catch { ...reconnect here... }
(在您的服务合约中,您只有IsAlive()
返回true)
答案 3 :(得分:0)
我将事件处理程序附加到client.InnerChannel.faulted
,然后将reliableSession
缩减为 20 秒。在事件处理程序中,我删除了现有的处理程序,然后运行异步方法尝试再次连接并再次附加事件处理程序。似乎工作。
答案 4 :(得分:0)
我遇到了同样的问题,在使用net.pipe *:// localhost / serviceName *时,我通过查看自托管应用程序的过程解决了这个问题。
我这样做的方式是使用实用程序类,这是代码。
public static class ServiceLocator
{
public static bool IsWcfStarted()
{
Process[] ProcessList = Process.GetProcesses();
return ProcessList.Any(a => a.ProcessName.StartsWith("MyApplication.Service.Host", StringComparison.Ordinal));
}
public static void StartWcfHost()
{
string path = System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var Process2 = new Process();
var Start2 = new ProcessStartInfo();
Start2.FileName = Path.Combine(path, "Service", "MyApplication.Service.Host.exe");
Process2.StartInfo = Start2;
Process2.Start();
}
}
现在,我的应用程序并没有被称为MyApplication,但你明白我的意思...... 现在在我的客户端使用主机的应用程序我有这个电话:
if (!ServiceLocator.IsWcfStarted())
{
WriteEventlog("First instance of WCF Client... starting WCF host.")
ServiceLocator.StartWcfHost();
int timeout=0;
while (!ServiceLocator.IsWcfStarted())
{
timeout++;
if(timeout> MAX_RETRY)
{
//show message that probably wcf host is not available, end the client
....
}
}
}
这解决了2个问题, 1.由于竞争条件我已经消失的代码错误,2 2.如果主机由于某些问题或配置错误而崩溃,我以受控的方式知道。
希望它有所帮助。
沃尔特