【问题标题】:WCF NamedPipe CommunicationException - "The pipe has been ended. (109, 0x6d)."WCF NamedPipe CommunicationException -“管道已结束。(109,0x6d)。”
【发布时间】:2013-03-28 00:03:43
【问题描述】:

我正在编写一个带有“状态工具”的 Windows 服务。该服务托管一个 WCF 命名管道端点,用于进程间通信。通过命名管道,状态工具可以定期向服务查询最新的“状态”。

在我的开发机器上,我有多个 IP 地址;其中之一是具有 192.168.1.XX 地址的“本地”网络。另一个是“公司”网络,地址为 10.0.X.XX。 Windows 服务在单个 IP 地址上收集 UDP 多播流量。

到目前为止,只要 Windows 服务使用“192.168.1.XX”地址,它就可以正常工作。它始终如一地向客户端正确报告状态。

当我切换到另一个“公司”IP 地址 (10.0.X.XX) 并重新启动服务时,我在检索状态时收到连续的“CommunicationExceptions”:

"There was an error reading from the pipe: The pipe has been ended. (109, 0x6d)."

现在,我认为 UDP 客户端的“已声明”IP 地址与 Named-Pipe 接口的功能没有任何关系;它们是应用程序的完全独立部分!

以下是相关的 WCF 配置部分:

//On the Client app:
string myNamedPipe = "net.pipe://127.0.0.1/MyNamedPipe";
ChannelFactory<IMyService> proxyFactory =
    new ChannelFactory<IMyService>(
        new NetNamedPipeBinding(),
        new EndpointAddress(myNamedPipe));


//On the Windows Service:
string myNamedPipe = "net.pipe://127.0.0.1/MyNamedPipe";
myService = new MyService(myCustomArgs);
serviceContractHost = new ServiceHost(myService );
serviceContractHost.AddServiceEndpoint(
    typeof(IMyService),
    new NetNamedPipeBinding(),
    myNamedPipe);

serviceContractHost.Open();

我不认为这是一个“权限”问题 - 我正在以管理权限运行客户端 - 但可能有一些特定于域的原因导致此问题中断?

【问题讨论】:

  • 异常堆栈跟踪是什么样的?你确定没有其他改变吗?切换服务配置后是否重启了状态工具?您能否发布您的状态工具代码部分,它实例化您的 rpoxy 并进行 WCF 调用?
  • 我会在星期一恢复工作时更新这个问题。也有朋友提出,IP地址可能是红鲱鱼,真正的区别可能是特定Enums的返回值。我也会对此进行调查。

标签: c# wcf windows-services named-pipes


【解决方案1】:

事实证明,IP 地址完全是一条红鲱鱼。

异常的真正原因是 WCF 服务返回的 Enum 值无效。

我的枚举是这样定义的:

[DataContract]
public enum MyEnumValues : Byte
{
    [EnumMember]
    Enum1 = 0x10,
    [EnumMember]
    Enum2 = 0x20,
    [EnumMember]
    Enum3 = 0x30,
    [EnumMember]
    Enum4 = 0x40,
} 

表面上看起来不错。

但是底层服务报告的原始状态是一个字节值“0”,并且没有对应的枚举值来转换它。

一旦我确保 Enum 值都有效,该工具就会像圣诞树一样亮起来。

如有疑问,请假设您的 WCF 数据无效。

【讨论】:

  • 跟踪文件中是否有任何指向此问题的内容,或者我们是否遇到了一般的“管道已结束”错误,需要扫描所有涉及的代码以希望找到潜在的序列化问题?
  • 我必须扫描所有数据并手动验证。我希望你有更好的运气,有用的痕迹!
  • "如有疑问,请假设您的 WCF 数据无效。" - 拯救了我的一天:)
  • 我因为忘记在每个枚举值上加上 [EnumMember] 前缀而得到了同样的错误。
【解决方案2】:

此异常表示服务器端存在序列化问题。

可以通过查看跟踪文件 (svclog) 解决此问题。要启用跟踪,请使用以下配置:

<system.diagnostics>
        <sources>
            <source name="System.ServiceModel" switchValue="Information, ActivityTracing" propagateActivity="false">
                <listeners>
                    <add name="traceListener" />
                </listeners>
            </source>
            <source name="System.ServiceModel.MessageLogging">
                <listeners>
                    <add name="traceListener" />
                </listeners>
            </source>
        </sources>
        <sharedListeners>
            <add name="traceListener" type="System.Diagnostics.XmlWriterTraceListener" initializeData="C:\Remos\Log\WcfTraceServer.svclog" />
        </sharedListeners>
    </system.diagnostics>

在我的例子中,我正在序列化一个不在枚举中的值。

【讨论】:

    【解决方案3】:

    有时这个错误是由对象的多态特性引起的。例如以下服务的方法将返回人员列表:

    [OperationContract]
     List<Person> GetEmployee();
    

    如果我们有从 Person 类继承的 Supervisor 类,并且上面的方法尝试返回 Supervisor 对象,WCF 序列化器类无法解释响应,因此会引发此错误
    此问题的解决方案是使用“已知类型”“服务已知类型”。我们必须指定隐式对象可以使用方法或服务进行交互。 对于我的示例,我们可以将 ServiceKnownType 属性放在方法或服务声明中,如下代码:

    [OperationContract]
    [ServiceKnownType(typeof(Supervisor))]
    List<Person> GetEmployee();
    

    【讨论】:

      【解决方案4】:

      遇到同样的问题There was an error reading from the pipe: Unrecognized error 109 (0x6d).

      • 一个原因是客户端和服务器 &lt;netNamedPipeBinding&gt; &lt;security mode="None"&gt;&lt;/security&gt;... 之间的绑定不一致(无通信)
      • 另一个间歇性问题与超时有关。

      两者都有相同的顶部错误消息。

      增加服务器和客户端绑定中的超时可阻止问题再次出现。

      绑定超时设置过低:

      sendTimeout="00:00:05" receiveTimeout="00:00:05"
      

      堆栈跟踪: at System.ServiceModel.Channels.StreamConnection.Read(Byte[] buffer, Int32 offset, Int32 size, TimeSpan timeout) at System.ServiceModel.Channels.SessionConnectionReader.Receive(TimeSpan timeout) at System.ServiceModel.Channels.SynchronizedMessageSource.Receive(TimeSpan timeout) at System.ServiceModel.Channels.TransportDuplexSessionChannel.Receive(TimeSpan timeout) at System.ServiceModel.Channels.TransportDuplexSessionChannel.TryReceive(TimeSpan timeout, Message& message) at System.ServiceModel.Dispatcher.DuplexChannelBinder.Request(Message message, TimeSpan timeout) at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout) at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs) at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation) at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

      【讨论】:

        【解决方案5】:

        当返回的有效负载太大时,这发生在我的 WCF 服务中。通过在 app.config 的 serviceBehavior 中添加它来修复它:

        <dataContractSerializer maxItemsInObjectGraph="[some big number]" />
        

        【讨论】:

          【解决方案6】:

          当服务操作抛出并且通道实际上出现故障时,我收到了这个错误。在您的情况下,您已经验证了服务操作本身正确完成并且只有返回抛出,但如果有疑问,请确保服务操作运行正常。

          【讨论】:

            【解决方案7】:

            我有很多没有 set{ } 的属性。添加这个解决了我的问题。

            【讨论】:

              【解决方案8】:

              同样的问题,但感谢Wojciech's answer

              我不得不做更多的挖掘工作才能找到放置 &lt;security&gt; 标记的位置,所以下面是 system.serviceModel 部分的开头现在的样子...

              <system.serviceModel>
                 <bindings>
                   <netNamedPipeBinding>
                     <binding>
                       <security mode="None"></security>
                     </binding>
                   </netNamedPipeBinding>
                 </bindings>
                 ....
              

              【讨论】:

                【解决方案9】:

                我遇到了这个问题,因为我使用的是older tutorial,并尝试以编程方式进行配置。

                我缺少的部分是提供元数据端点 (thank you, this post!)。

                ServiceMetadataBehavior serviceMetadataBehavior = 
                    host.Description.Behaviors.Find<ServiceMetadataBehavior>();
                
                if (serviceMetadataBehavior == null)
                {
                    serviceMetadataBehavior = new ServiceMetadataBehavior();
                    host.Description.Behaviors.Add(serviceMetadataBehavior);
                }
                
                host.AddServiceEndpoint(
                    typeof(IMetadataExchange), 
                    MetadataExchangeBindings.CreateMexNamedPipeBinding(), 
                    "net.pipe://localhost/PipeReverse/mex"
                );
                

                【讨论】:

                  【解决方案10】:

                  此外,我们的代码正在序列化 Dictionary&lt;string, List&lt;int&gt;&gt;。这似乎引起了问题。用[DataContract] 标记类和要序列化的每个公共属性(包括字典)为我们解决了这个问题。

                  <DataContract>
                  Public Class QueryConfig
                  
                      <DataMember>
                      Public SegmentTypes As List(Of SegmentType)
                  
                      <DataMember>
                      Public Events As Dictionary(Of String, List(Of Integer))
                  
                      <DataMember>
                      Public Enabled As Boolean
                  
                      <DataMember>
                      Public Name As String
                  

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 2019-12-30
                    • 1970-01-01
                    • 2018-11-23
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2022-10-06
                    相关资源
                    最近更新 更多