通信对象 System.ServiceModel.Channels.ServiceChannel 不能用于通信

通信对象 System.ServiceModel.Channels, 不能用于通信,因为它处于“错误”状态。

这个错误到底是怎么回事,我该怎么解决呢?

356125 次浏览

之所以会出现这个错误,是因为您让。NET 异常发生在您的服务器端,您没有捕获和处理它,也没有将它转换为 SOAP 错误。

现在由于服务器端“崩溃”了,WCF 运行时“故障”了通道——例如客户端和服务器之间的通信链路不可用——毕竟,看起来你的服务器刚刚崩溃了,所以你不能再和它通信了。

所以你需要做的是:

  • 总是 捕获并处理服务器端错误-不要 let。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
    }
    

    如果是,那么您所能做的就是释放它并重新创建客户端代理,然后再试一次

事实上,如果在遵循 Marc _ s的建议之后不成功,请记住,服务器上 web.config 中的服务器绑定配置(或缺少)中的 < security > 元素可能会导致此异常。例如,服务器需要 Message级别的安全性,客户机配置为 None(或者,如果服务器不是 ActiveDirectory 域的一部分,但远程客户机主机是)。

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

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

  1. 使用 FaultException (这个异常对于 WCF 来说并不意外,因此 WCF 知道服务器仍然处于有效状态)
    而不是

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

    经常使用

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

    也许您可以尝试. . catch 整个块并在所有 Exception 的情况下抛出 FaultException

    try
    {
    ... some code here
    }
    catch (Exception ex)
    {
    throw new FaultException(ex.Message)
    }
    
  2. Tell WCF to handle all Exceptions using an Errorhandler. This can be done in several ways, I chose a simple one using an Attribute:
    All we have to do more, is to use the attribute [SvcErrorHandlerBehaviour] on the wanted Service Implementation

    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);
    }
    }
    }
    

This is an easy example, you can dive deeper into IErrorhandler by not using the naked FaultException, but a FaultException<> with a type that provides additional info see IErrorHandler for an detailed example.

我还有一个问题,我想在其他答案中没有提到过。

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

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

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

抛出的原始异常的错误消息要比“ . . it is in The Fault state”好得多

例如,我从 ServiceHost 获得了这个异常。Open () ,但是当我在抛出异常时捕获到原始异常时,错误消息是:

服务“ MyServiceName”没有应用程序(非基础设施) 这可能是因为没有找到配置文件 或者因为没有服务元素与 服务名称可以在配置文件中找到,或者因为没有 在 service 元素中定义了端点。

在 App.config 中修复拼写错误解决了这个问题。

在我的例子中,原因是一些无法加载的错误证书。我是从系统下的事件查看器中了解到的:

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

此错误也可由您自己的计算机触发,而不仅仅是未处理的异常。如果您的服务器/计算机的时钟时间关闭太多分钟,许多。NET Web 服务将拒绝您的请求,并出现未处理的错误。这是从他们的角度来处理的,但是从你的角度来看没有处理过。检查以确保接收服务器的时钟时间是正确的。如果需要修复,您必须在通道重新打开之前重置您的服务或重新启动。

我在一台服务器上遇到了这个问题,防火墙阻止了互联网时间的更新,服务器由于某种原因停机了。所有的第三方。NET Web 服务出现故障,因为它们拒绝了任何 Web 服务请求。深入研究事件查看器有助于识别问题,但调整时钟解决了问题。即使我们收到了用于未来 Web 服务调用的错误状态错误消息,错误仍在我们这一端。

服务器将自动中止在接收超时(默认时间为10分钟)期间没有收到任何消息的连接。这是一个 DoS 缓解措施,以防止客户机强制服务器在无限长的时间内打开连接。

由于服务器中止了连接,因为它已经空闲,客户端得到这个异常。

通过在服务器绑定上配置接收超时,可以控制服务器在中止连接之前允许空闲的时间长度。 提供者: T.R.Vishwanath-MSFT

我在尝试使用 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>

我的案例中的第二个问题是,我在我的源 WCF 服务上使用了 transferMode="Streamed",而在客户机上我没有关于它的任何具体信息,这很糟糕,因为默认的 transferModeBuffered,在源和客户机上以相同的方式配置非常重要。

我知道这是一个较老的职位,但一件事要注意,当你不能改变的安全是,以确保您的用户名和密码设置。

我有一个名为 UserNameOverTransport 的 enticationMode 服务,如果没有为服务客户端设置用户名和密码,我将得到这个错误。

对我来说,这是一个负载平衡器/url 问题。负载均衡器后面的 Web 服务使用完整的 URL (如 loadbalancer.mycompany.com)调用同一负载均衡器后面的另一个服务。我改变了它,以绕过负载平衡器时调用第二个服务使用 localhost.mycompany.com代替。

我认为负载平衡器存在某种循环参考问题。

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

之前

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

之后

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

我们正在我们的系统中使用 MSMQ,这个错误消息来了。原因是我们的队列已经满了,而且我们没有正确处理错误日志记录机制,所以我们得到了上面的异常,而不是 msmq ful。我们清除的消息,然后它的工作正常。

对我们来说,问题是该网站没有白名单,我们的应用程序需要达到。网站被列入白名单后,错误就消失了。