我正在编写一个小型WCF托管引擎,它将根据.config文件动态创建ServiceHosts。一般的想法是允许我们在运行时删除现有服务以及添加新服务,而无需使我们的所有服务脱机。

我遇到了问题单元测试,表明这可能不像听起来那么容易。对于任何给定的端点,似乎只存在一个ServiceHost(即使服务的多个不同端点可能存在于单个ServiceHost中)。这通常不是问题,但是当需要重新配置服务时,关闭原始ServiceHost实际上并不会终止该端点地址的注册。尝试为同一服务创建另一个ServiceHost(这意味着使用相同的端点)失败,但出现以下异常:

System.InvalidOperationException: The ChannelDispatcher at 'net.pipe://localhost/' with contract(s) '"ITestService"' is unable to open its IChannelListener. --->
System.InvalidOperationException: A registration already exists for URI 'net.pipe://localhost/'.

我实际上是在单元测试期间遇到错误。测试将运行一个单元,完全关闭ServiceHosts并尽可能多地托管引擎。然后创建托管引擎的另一个实例,该实例尝试再次为不同的测试重新创建相同的ServiceHost。第二次测试遇到上述错误。我猜测,虽然ServiceHost.Close()被调用,但实际上并没有破坏服务主机......所以它仍然在内存中徘徊。我无法判断GC是否正在清理旧的服务主机......问题在最初发生后仍然存在而不会消失(最好我能够确定......到目前为止我已经等了大约30分钟。 )

我的system.serviceModel配置文件如下:

  <system.serviceModel>
    <services>
      <service name="Campus.Core.ServiceModel.TestServiceStub">
        <endpoint          
          address="net.pipe://localhost"          
          binding="netNamedPipeBinding"           
          contract="Campus.Core.ServiceModel.ITestService"
        />
      </service>
    </services>
  </system.serviceModel>
有帮助吗?

解决方案

提供此问题的答案,以防其他人遇到此问题。事实证明这个问题有两个原因,如下所示:

1)在单元测试期间,如果遇到异常,通常会在ServiceHost关闭之前中断测试代码。这使ServiceHost绑定到特定端点。这导致所有后续测试失败,因为它们执行相同的代码。当我使用SubSpec和xUnit进行BDD时,单个测试用例(BDD术语中的关注)执行单个断言每个测试,并且单个测试用例可以包含多达十几个断言。

2)注意MEX端点。 MEX端点每个服务只能存在一次。最初,我创建了一个http和net.tcp mex端点。然而,这导致了一个问题,因为MEX端点启动的第二个实例引发了异常。一般来说,如果您使用MEX端点,HTTP是最有用的协议,除非存在一些阻止您这样做的物理基础结构问题。

一般来说,在ServiceHost上调用Close()方法将完全取消绑定它,允许以前绑定到其端点的任何地址再次可用。有时关闭可能需要一段时间,在极少数情况下,可能会抛出异常。如果您正在使用SubSpec执行BDD并遵循每个测试的单个断言规则,则在一个测试中抛出的异常会阻止ServiceHosts关闭,这将导致所有后续测试失败。

其他提示

一个答案是每次旋转一个Guid时将Guid附加到服务主机的URL,并使用工厂方法同时旋转ServiceHost实例并返回客户端通道,以便客户端知道哪个网址使用。

IDesign的InProcFactory示例使用此方法,因此您可以按原样使用它:

http://www.idesign.net/idesign/DesktopDefault的.aspx的tabindex = 5&安培; tabid = 11

请注意,您必须在IDesign的网站上注册才能下载样本,他们会偶尔向您发送有关培训等的公告,但这并不算太多。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top