如何确定WCF服务已准备好?

时间:2011-03-22 13:18:29

标签: c# wcf

我有以下情况:

我的主应用程序(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();

如何确保服务准备就绪而无需等待一段时间?

5 个答案:

答案 0 :(得分:6)

如果一般情况是您只是在等待其他服务启动,那么您也可以使用在您的界面上执行“Ping”方法的方法,该方法不执行任何操作,并在重新开始响应之前重试。

我们做了类似的事情:我们尝试在启动时在循环中调用ping方法(重试之间为1秒),在我们的日志中记录(但最终忽略)尝试访问我们的服务时发生的任何TargetInvocationException 。一旦我们得到第一个正确的答案,我们继续进行。

当然,这仅涵盖启动预热案例 - 成功ping后服务可能会停止,或者我们可能因“服务未就绪”之外的原因而获得TargetInvocationException

答案 1 :(得分:5)

一旦服务主机完全打开并且通道监听器的Opened事件被触发,您可以使服务信号成为事件[编辑 - 请参阅注释]。应用程序将在使用其代理之前等待事件。


注意:使用命名事件很简单,因为.NET类型EventWaitHandle为您提供了所需的一切。使用匿名事件是可取的,但需要更多工作,因为.NET事件包装器类型不会为您提供可继承的事件句柄。但是,如果您自己P / Invoke Windows DuplicateHandle API以获取可继承的句柄,然后在其命令行参数中将重复的句柄值传递给子进程,则仍然可以。

答案 2 :(得分:2)

  1. 如果您使用的是.Net 4.0,则可以使用WS-Discovery使服务通过广播IP宣布其存在。

  2. 该服务还可以将消息发送到队列(MSMQ绑定),其寿命很短,比如几秒钟,客户端可以监控。

  3. 让服务创建一个信号文件,然后在客户端使用FileSystemWatcher来检测它何时被创建。

  4. 只需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.如果主机由于某些问题或配置错误而崩溃,我以受控的方式知道。

希望它有所帮助。

沃尔特