Answers:
之所以会出现此错误,是因为您在服务器端发生了.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
}
如果是这样,您所能做的就是处置它,然后重新创建客户端代理,然后重试。
为防止服务器进入故障状态,必须确保不会引发未处理的异常。如果WCF看到意外的异常,则不再接受任何呼叫-安全第一。
有两种避免这种行为的可能性:
使用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)
}
告诉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,以获取详细示例。
若要诊断此问题,请在Visual Studio调试器下运行该服务。使用菜单:Debug | Exceptions并指示要抛出异常时中断。
引发的原始异常比“ ..它处于故障状态”具有更好的错误消息。
例如,我从ServiceHost.Open()获取此异常,但是当我在引发原始异常时捕获了该异常时,错误消息为:
服务“ MyServiceName”的应用程序端点(非基础结构)为零。这可能是因为没有为您的应用程序找到配置文件,或者是因为在配置文件中找不到与服务名称匹配的服务元素,或者因为在服务元素中未定义端点。
解决App.config中的拼写错误可以解决此问题。
尝试在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服务上使用的客户端中没有任何具体信息,这很糟糕,因为默认值transferMode
是Buffered
并且在同一位置配置源和客户端都很重要方式。
如果从Visual Studio调试中看到此消息,则解决方案包含WCF项目。然后打开此WCF项目设置->转到“ WCF选项”选项卡->关闭“调试时启动WCF服务主机...”选项
对我来说,问题是由导入WSDL自动生成的配置文件引起的。我将绑定从basicHttpBinding更新为customBinding。添加其他异常处理无助于指出这一点。
之前
<basicHttpBinding>
<binding name="ServiceName">
<security mode="Transport" />
</binding>
</basicHttpBinding>`
后
<customBinding>
<binding name="ServiceName">
<textMessageEncoding messageVersion="Soap12" />
<httpsTransport />
</binding>
</customBinding>`
您也可以由您自己的计算机触发此错误,而不仅仅是未处理的异常。如果您的服务器/计算机的时钟时间间隔过长,那么许多.NET Web服务将以未处理的错误拒绝您的请求。从他们的角度来处理,但从您的角度来处理。检查以确保接收服务器的时钟时间正确。如果需要修复,则必须重新设置服务或重新启动频道才能重新打开。
我在防火墙阻止Internet时间更新的服务器上遇到了此问题,并且服务器由于某种原因下了时间。所有第三方.NET Web服务都出现故障,因为它们拒绝了任何Web服务请求。深入研究事件查看器有助于发现问题,但是调整时钟可以解决问题。即使我们收到了将来的Web服务调用的“故障状态”错误消息,该错误仍在我们的末端。
服务器将自动终止在等于接收超时(默认值为10分钟)的时间内未收到任何消息的连接。这是一个DoS缓解措施,可以防止客户端强制服务器无限期地打开连接。
由于服务器由于已变为空闲状态而中止了连接,因此客户端会收到此异常。
您可以通过在服务器绑定上配置接收超时来控制服务器允许连接空闲多长时间后再中止连接。图片来源:TRVishwanath-MSFT
对我而言,这是一个负载平衡器/ URL问题。负载均衡器后面的Web服务使用完整的URL调用了同一负载均衡器后面的另一个服务loadbalancer.mycompany.com
。我改为通过调用第二个服务来绕过负载均衡器localhost.mycompany.com
。
我认为负载均衡器正在发生某种循环参考问题。
不是解决此问题的方法,但是如果您遇到Ektron eSync的上述错误,则可能是数据库磁盘空间不足。
编辑:实际上,这并非完全是Ektron eSync唯一的问题。这可能在查询完整数据库的任何服务上发生。
编辑:磁盘空间不足或阻止访问所需的目录将导致此问题。