通信对象System.ServiceModel.Channels.ServiceChannel无法用于通信


156

通信对象System.ServiceModel.Channels.ServiceChannel不能用于通信,因为它处于故障状态。

这个错误到底有什么意义,我将如何解决呢?

Answers:


151

之所以会出现此错误,是因为您在服务器端发生了.NET异常,并且您没有捕获并处理它,也没有将其转换为SOAP错误。

现在,由于服务器端被“炸毁”,WCF运行时已“破坏”了通道-例如,客户端和服务器之间的通信链接不可用-毕竟,看起来您的服务器刚刚被炸毁,因此您无法与之通信它了。

因此,您需要做的是:

  • 始终捕获并处理服务器端错误- 不要让.NET异常从服务器传播到客户端- 始终将这些错误包装为可互操作的SOAP错误。出WCF IErrorHandler接口,并在服务器端实现它

  • 如果您要从客户端向您的频道发送第二条消息,请确保该频道未处于故障状态:

    if(client.InnerChannel.State != System.ServiceModel.CommunicationState.Faulted)
    {
       // call service - everything's fine
    }
    else
    {
       // channel faulted - re-create your client and then try again
    }

    如果是这样,您所能做的就是处置它,然后重新创建客户端代理,然后重试。


11
当问题也出现在客户端时,似乎也会发生相同的错误:例如,超过了传入消息的消息大小配额。
svick 2012年

6
如何重新创建客户端?
Masoud 2015年

32

为防止服务器进入故障状态,必须确保不会引发未处理的异常。如果WCF看到意外的异常,则不再接受任何呼叫-安全第一。
有两种避免这种行为的可能性:

  1. 使用FaultException(对于WCF,这不是意外的,因此WCF知道服务器仍处于有效状态),
    而不是

    throw new Exception("Error xy in my function")  

    始终使用

    throw new FaultException("Error xy in my function")  

    也许你可以尝试..catch整个块并在所有异常情况下抛出FaultException

    try   
    {  
        ... some code here   
    }
    catch (Exception ex)
    {  
        throw new FaultException(ex.Message)   
    }
  2. 告诉WCF使用Errorhandler处理所有异常。这可以通过几种方式完成,我选择了一个使用属性的简单方法:
    我们要做的就是[SvcErrorHandlerBehaviour]在所需的服务实现上使用该属性。

    using System;
    using System.Collections.ObjectModel;
    using System.ServiceModel;
    using System.ServiceModel.Channels;
    using System.ServiceModel.Description;
    using System.ServiceModel.Dispatcher;
    
    namespace MainService.Services
    {
        /// <summary>
        /// Provides FaultExceptions for all Methods Calls of a Service that fails with an Exception
        /// </summary>
        public class SvcErrorHandlerBehaviourAttribute : Attribute, IServiceBehavior
        {
            public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
            { } //implementation not needed
    
            public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints,
                                             BindingParameterCollection bindingParameters)
            { } //implementation not needed
    
            public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
            {
                foreach (ChannelDispatcherBase chanDispBase in serviceHostBase.ChannelDispatchers)
                {
                    ChannelDispatcher channelDispatcher = chanDispBase as ChannelDispatcher;
                    if (channelDispatcher == null)
                        continue;
                    channelDispatcher.ErrorHandlers.Add(new SvcErrorHandler());
                }
            }
        }
    
        public class SvcErrorHandler: IErrorHandler
        {
            public bool HandleError(Exception error)
            {
                //You can log th message if you want.
                return true;
            }
    
            public void ProvideFault(Exception error, MessageVersion version, ref Message msg)
            {
                if (error is FaultException)
                    return;
    
                FaultException faultException = new FaultException(error.Message);
                MessageFault messageFault = faultException.CreateMessageFault();
                msg = Message.CreateMessage(version, messageFault, faultException.Action);
            }
        }
    }

这是一个简单的示例,您可以通过不使用Naked来更深入地了解IErrorhandler FaultException,但可以FaultException<>使用提供其他信息的类型来查看IErrorHandler,以获取详细示例。


10

实际上,如果在遵循marc_s的建议后失败,请记住,服务器上web.config中服务器绑定配置中的<security>元素(或缺少该元素)可能会导致此异常。例如,服务器期望达到Message级别的安全性,并且将客户端配置为None(或,如果服务器不是Active Directory域的一部分,而远程客户端主机则是)。

提示:在这种情况下,在RDP会话中的管理帐户下直接在服务器计算机上直接执行时,客户端应用很可能会调用Web服务。


2

若要诊断此问题,请在Visual Studio调试器下运行该服务。使用菜单:Debug | Exceptions并指示要抛出异常时中断。

引发的原始异常比“ ..它处于故障状态”具有更好的错误消息。

例如,我从ServiceHost.Open()获取此异常,但是当我在引发原始异常时捕获了该异常时,错误消息为:

服务“ MyServiceName”的应用程序端点(非基础结构)为零。这可能是因为没有为您的应用程序找到配置文件,或者是因为在配置文件中找不到与服务名称匹配的服务元素,或者因为在服务元素中未定义端点。

解决App.config中的拼写错误可以解决此问题。


在VS2015中,选择“调试”→“异常设置”,然后勾选“公共语言运行时异常”。
SharpC

1
那么,为什么在使用Visual Studio调试器之前没有给出原始异常?
耶斯

2

尝试在http asmx服务中使用net.tcp wcf服务端点时遇到相同的问题。

如我所见,没有人写出具体的答案,为什么会出现此问题,而只是如何正确处理。

我已经连续几天苦苦挣扎,最后我发现问题出在我的案例中。

最初,我认为当您引用服务时,配置文件的配置方式将与源代码中的安全标记相同,但事实并非如此,我应该手动进行处理。就我而言,我只有

<netTcpBinding>
    <binding name="NetTcpBinding_IAuthenticationLoggerService"
    </binding>
</netTcpBinding>`

后来我看到安全部分丢失了,应该看起来像这样

<netTcpBinding>
    <binding name="NetTcpBinding_IAuthenticationLoggerService" transferMode="Buffered">
      <security mode="None">
        <transport clientCredentialType="None"/>
      </security>
    </binding>
  </netTcpBinding>

在我的情况下,第二个问题是我transferMode="Streamed"在源WCF服务上使用的客户端中没有任何具体信息,这很糟糕,因为默认值transferModeBuffered并且在同一位置配置源和客户端都很重要方式。


1

我还有另一个问题,我认为其他答案中没有提到。

我必须在相同的tcp地址和端口上服务端点。在app.config中,我忘记添加两个端点,因此该服务在正确的端口上运行,但服务接口错误。


1

如果从Visual Studio调试中看到此消息,则解决方案包含WCF项目。然后打开此WCF项目设置->转到“ WCF选项”选项卡->关闭“调试时启动WCF服务主机...”选项


我遇到了同样的问题,并且在这个问题上停留了很长时间。将客户端和服务器都放在同一个解决方案上可能不是一个好习惯。谢谢!
yoosha

1

对我来说,问题是由导入WSDL自动生成的配置文件引起的。我将绑定从basicHttpBinding更新为customBinding。添加其他异常处理无助于指出这一点。

之前

<basicHttpBinding>
            <binding name="ServiceName">
                <security mode="Transport" />
            </binding>
        </basicHttpBinding>`

<customBinding>
        <binding name="ServiceName">
          <textMessageEncoding messageVersion="Soap12" />
          <httpsTransport />
        </binding>
      </customBinding>`

0

在我的情况下,原因是某些错误的证书无法加载。我从“事件查看器”的“系统”下找到了它:

尝试访问TLS服务器凭据私钥时发生致命错误。从加密模块返回的错误代码为0x8009030D。内部错误状态为10001。


0

您也可以由您自己的计算机触发此错误,而不仅仅是未处理的异常。如果您的服务器/计算机的时钟时间间隔过长,那么许多.NET Web服务将以未处理的错误拒绝您的请求。从他们的角度来处理,但从您的角度来处理。检查以确保接收服务器的时钟时间正确。如果需要修复,则必须重新设置服务或重新启动频道才能重新打开。

我在防火墙阻止Internet时间更新的服务器上遇到了此问题,并且服务器由于某种原因下了时间。所有第三方.NET Web服务都出现故障,因为它们拒绝了任何Web服务请求。深入研究事件查看器有助于发现问题,但是调整时钟可以解决问题。即使我们收到了将来的Web服务调用的“故障状态”错误消息,该错误仍在我们的末端。


0

服务器将自动终止在等于接收超时(默认值为10分钟)的时间内未收到任何消息的连接。这是一个DoS缓解措施,可以防止客户端强制服务器无限期地打开连接。

由于服务器由于已变为空闲状态而中止了连接,因此客户端会收到此异常。

您可以通过在服务器绑定上配置接收超时来控制服务器允许连接空闲多长时间后再中止连接。图片来源:TRVishwanath-MSFT


0

我知道这是一篇较旧的文章,但是当您无法更改安全性时要提防的一件事是确保设置了用户名和密码。

我有一个身份验证模式为UserNameOverTransport的服务,当未为服务客户端设置用户名和密码时,会出现此错误。


0

对我而言,这是一个负载平衡器/ URL问题。负载均衡器后面的Web服务使用完整的URL调用了同一负载均衡器后面的另一个服务loadbalancer.mycompany.com。我改为通过调用第二个服务来绕过负载均衡器localhost.mycompany.com

我认为负载均衡器正在发生某种循环参考问题。


-2

不是解决此问题的方法,但是如果您遇到Ektron eSync的上述错误,则可能是数据库磁盘空间不足。

编辑:实际上,这并非完全是Ektron eSync唯一的问题。这可能在查询完整数据库的任何服务上发生。

编辑:磁盘空间不足或阻止访问所需的目录将导致此问题。


这不能为问题提供答案。要批评或要求作者澄清,请在其帖子下方留下评论-您可以随时对自己的帖子发表评论,一旦您有足够的声誉,就可以在任何帖子中发表评论
Dariusz

2
我回答了他的问题“我将如何解决它?”,这不是我的错,他从未向我们提供有关是否使用Ektron的详细信息。我还要求50名代表对他的帖子发表评论。
乔纳森·比克
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.