本主题列出了开发 WCF 客户端和服务时客户可能会遇到的一些已知问题。 如果遇到的问题不在此列表中,建议为服务配置跟踪。 这将生成一个跟踪文件,可以使用跟踪文件查看器查看,并获取有关服务中可能发生的异常的详细信息。 有关配置跟踪的详细信息,请参阅: 配置跟踪。 有关跟踪文件查看器的详细信息,请参阅: 服务跟踪查看器工具(SvcTraceViewer.exe)。
安装 Windows 7 和 IIS 后,尝试浏览到 WCF 服务时,会收到以下错误消息:HTTP 错误 404.3 - 找不到
HTTP 错误 404.3 – 由于扩展配置,无法提供所请求的页面。 如果页面是脚本,请添加处理程序。 如果应下载该文件,请添加 MIME 映射。 详细错误 InformationModule StaticFileModule。
有时,如果客户端在第一次请求之后一段时间处于空闲状态,则会在第二个请求上收到 MessageSecurityException。 发生了什么事情?
当我引发一个类型为异常的 FaultException<Exception> 时,我总是在客户端上接收到一个常规 FaultException 类型,而不是泛型类型。 发生了什么事情?
我在服务中使用 X.509 证书,遇到了 System.Security.Cryptography.CryptographicException。 发生了什么事情?
安装 Windows 7 和 IIS 后,尝试浏览到 WCF 服务时,会收到以下错误消息:HTTP 错误 404.3 - 找不到
完整错误消息为:
HTTP 错误 404.3 – 由于扩展配置,无法提供所请求的页面。 如果页面是脚本,请添加处理程序。 如果应下载该文件,请添加 MIME 映射。 详细错误 InformationModule StaticFileModule。
如果未在控制面板中显式设置“Windows Communication Foundation HTTP 激活”,则会出现此错误消息。 要进行此设置,请前往控制面板,然后单击窗口左下角的程序。 单击“打开或关闭 Windows 功能”。 展开 Microsoft .NET Framework 3.5.1 并选择 Windows Communication Foundation HTTP 激活。
有时,如果客户端在第一次请求之后一段时间处于空闲状态,则会在第二个请求上收到 MessageSecurityException。 发生了什么事情?
第二个请求通常可能由于两个原因而失败:(1)会话已超时,或(2)托管该服务的 Web 服务器正在被回收。 在第一种情况下,会话有效,直到服务超时。当服务在服务绑定中指定的时间段内未收到来自客户端的请求时,ReceiveTimeout服务将终止安全会话。 后续客户端消息会导致 MessageSecurityException。 客户端必须重新建立与服务的安全会话,才能发送以后的消息或使用有状态安全上下文令牌。 有状态的安全上下文令牌还允许安全会话在回收 Web 服务器后存在。 有关在安全会话中使用有状态安全上下文令牌的详细信息,请参阅 如何:为安全会话创建安全上下文令牌。 或者,可以禁用安全会话。 使用 <wsHttpBinding> 绑定时,可以将属性设置为establishSecurityContext
false
禁用安全会话。 若要禁用其他绑定的安全会话,必须创建自定义绑定。 有关创建自定义绑定的详细信息,请参阅 如何:使用 SecurityBindingElement 创建自定义绑定。 在应用上述任一选项之前,必须了解应用程序的安全要求。
大约 10 个客户端与之交互后,我的服务开始拒绝新客户端。 发生了什么事情?
默认情况下,服务只能有 10 个并发会话。 因此,如果服务绑定使用会话,则服务将接受新的客户端连接,直到达到该数字,之后它将拒绝新的客户端连接,直到当前会话之一结束。 可以通过多种方式支持更多客户端。 如果服务不需要会话,请不要使用会话绑定。 (有关详细信息,请参阅 “使用会话”。另一个选项是通过将属性的值更改为适合你的情况的数字 MaxConcurrentSessions 来增加会话限制。
是否可以从 WCF 应用程序的配置文件以外的某个位置加载服务配置?
可以,但是,必须创建自定义 ServiceHost 类来替代 ApplyConfiguration 该方法。 在该方法中,可以先调用基来加载配置(如果要加载标准配置信息),但也可以完全替换配置加载系统。 如果要从不同于应用程序配置文件的配置文件加载配置,则必须自行分析配置文件并加载配置。
下面的代码示例演示如何重写 ApplyConfiguration 方法,并直接配置一个端点。
public class MyServiceHost : ServiceHost
{
public MyServiceHost(Type serviceType, params Uri[] baseAddresses)
: base(serviceType, baseAddresses)
{
Console.WriteLine("MyServiceHost Constructor");
}
protected override void ApplyConfiguration()
{
string straddress = GetAddress();
Uri address = new Uri(straddress);
Binding binding = GetBinding();
base.AddServiceEndpoint(typeof(IData), binding, address);
}
string GetAddress()
{
return "http://MyMachine:7777/MyEndpointAddress/";
}
Binding GetBinding()
{
WSHttpBinding binding = new WSHttpBinding();
binding.Security.Mode = SecurityMode.None;
return binding;
}
}
我的服务和客户端工作非常出色,但是当客户端在另一台计算机上时,我无法让他们正常工作? 发生了什么事情?
根据例外情况,可能会有以下几个问题:
可能需要将客户端终结点地址更改为主机名,而不是“localhost”。
可能需要打开应用程序的端口。 有关详细信息,请参阅 SDK 示例中的 防火墙说明 。
有关其他可能的问题,请参阅主题 运行 Windows Communication Foundation 示例。
如果客户端使用的是 Windows 凭据并且异常为 SecurityNegotiationException,则按如下方式配置 Kerberos。
将身份凭据添加到客户端 App.config 文件中的终端元素:
<endpoint address="http://MyServer:8000/MyService/" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IServiceExample" contract="IServiceExample" behaviorConfiguration="ClientCredBehavior" name="WSHttpBinding_IServiceExample"> <identity> <userPrincipalName value="name@corp.contoso.com"/> </identity> </endpoint>
在系统或 NetworkService 帐户下运行自承载服务。 可以运行以下命令,在系统帐户下创建命令窗口:
at 12:36 /interactive "cmd.exe"
在 Internet Information Services(IIS)下托管服务,默认情况下使用服务主体名称(SPN)帐户。
使用 SetSPN 向域注册新的 SPN。 你需要是域管理员才能执行此作。
有关 Kerberos 协议的详细信息,请参阅 WCF 中使用的安全概念 ,以及:
Kerberos Explained(解释的 Kerberos)
当我引发一个类型为异常的 FaultException<Exception> 时,我总是在客户端上接收到一个常规 FaultException 类型,而不是泛型类型。 发生了什么事情?
强烈建议创建自己的自定义错误数据类型,并将其声明为错误协定中的详细信息类型。 之所以使用系统提供的异常类型,是因为:
创建一个类型依赖项,删除面向服务的应用程序的最大优势之一。
不能依赖以标准方式进行序列化的异常。 有些(例如 SecurityException)可能根本不可序列化。
向客户端公开内部实现详细信息。 有关详细信息,请参阅 在协定和服务中指定和处理错误。
但是,如果要调试应用程序,则可以序列化 ServiceDebugBehavior 异常信息,并使用类将其返回到客户端。
当答复不包含数据时,单向操作和请求-答复操作的返回速度似乎大致相同。 发生了什么情况?
指定某操作是一种单向操作仅仅意味着操作契约接受输入消息,并且不返回输出消息。 在 WCF 中,当出站数据已写入网络或引发异常时,所有客户端调用都将返回。 单向操作以相同方式工作,如果找不到服务则它们可以引发;或者如果服务没有准备好从网络接受数据则它们可以阻止。 通常,在 WCF 中,这会导致单向调用比请求-回复更快返回客户端;但是,任何导致通过网络慢速发送出站数据的情况都会同时减缓单向操作和请求-回复操作。 有关详细信息,请参阅 One-Way 服务和使用 WCF 客户端访问服务。
我在服务中使用 X.509 证书,遇到了 System.Security.Cryptography.CryptographicException。 发生了什么事情?
这通常在更改运行 IIS 工作进程的用户帐户后发生。 例如,在 Windows XP 中,如果将运行 Aspnet_wp.exe 的默认用户帐户从 ASPNET 更改为自定义用户帐户,可能会看到此错误。 如果使用私钥,则使用该私钥的进程需要有权访问存储该密钥的文件。
如果是这种情况,则必须为进程的帐户授予读取访问权限,以访问包含私钥的文件。 例如,如果 IIS 工作进程在 Bob 帐户下运行,则需要向 Bob 授予对包含私钥的文件的读取访问权限。
有关如何为包含特定 X.509 证书私钥的文件提供正确的用户帐户访问权限的详细信息,请参阅 如何:使 X.509 证书可供 WCF 访问。
我将操作的第一个参数从大写更改为小写,现在我的客户端抛出异常。 发生了什么情况?
操作签名中参数名称的值是合同的一部分,并且区分大小写。 使用System.ServiceModel.MessageParameterAttribute属性,当您需要区分本地参数名称与描述客户端应用程序操作的元数据时。
我正在使用我的跟踪工具之一,并且获得一个 EndpointNotFoundException。 发生了什么事情?
如果您使用的跟踪工具不是系统提供的 WCF 跟踪机制,并且收到一个指示地址筛选器不匹配的 EndpointNotFoundException,那么您需要使用 ClientViaBehavior 类将消息定向到跟踪实用工具,并让该实用工具将消息重定向到服务地址。
ClientViaBehavior 类更改 Via
寻址标头,以独立于最终接收方(由 To
寻址标头指示)指定下一个网络地址。 但是,执行此作时,请不要更改用于建立 To
值的终结点地址。
下面的代码示例演示了一个示例客户端配置文件。
<endpoint
address="http://localhost:8000/MyServer/"
binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_IMyContract"
behaviorConfiguration="MyClient"
contract="IMyContract"
name="WSHttpBinding_IMyContract">
</endpoint>
<behaviors>
<endpointBehaviors>
<behavior name="MyClient">
<clientVia viaUri="http://localhost:8001/MyServer/"/>
</behavior>
</endpointBehaviors>
</behaviors>
什么是基础地址? 它与终结点地址有何关联?
基址是类的 ServiceHost 根地址。 默认情况下,如果将一个 ServiceMetadataBehavior 类添加到您的服务配置中,主机发布的所有终结点的 Web 服务描述语言 (WSDL) 都将从 HTTP 基址、提供给元数据行为的任何相对地址以及“?wsdl”中检索。 如果熟悉 ASP.NET 和 IIS,则基址等效于虚拟目录。
使用 NetTcpBinding 在服务终结点与 mex 终结点之间共享端口
如果将服务的基址指定为 net.tcp://MyServer:8080/MyService,并添加以下端点:
<services>
<service name="Microsoft.Samples.NetTcp.CalculatorService">
<endpoint address="calcsvc" binding ="netTcpBinding" contract="Microsoft.Samples.NetTcp.ICalculator"/>
<endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />
</service>
</services>
如果按下面的配置代码段所示修改某个 NetTcpBinding 设置:
<bindings>
<netTcpBinding>
<binding closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions" hostNameComparisonMode="StrongWildcard" listenBacklog="10" maxBufferPoolSize="524288" maxBufferSize="65536" maxConnections="11" maxReceivedMessageSize="65536">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
<reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false"/>
<security mode="Transport">
<transport clientCredentialType="Windows" protectionLevel="EncryptAndSign"/>
</security>
</binding>
</netTcpBinding>
</bindings>
将看到如下错误:未处理的异常:System.ServiceModel.AddressAlreadyInUseException:IP 终结点 0.0.0.0.0:9000 上已有侦听器,可以通过为 MEX 终结点指定具有不同端口的完全限定 URL 来解决此问题,如以下配置代码片段所示:
<services>
<service name="Microsoft.Samples.NetTcp.CalculatorService">
<endpoint address="calcsvc" binding ="netTcpBinding" contract="Microsoft.Samples.NetTcp.ICalculator"/>
<endpoint address="net.tcp://localhost:9001/servicemodelsamples/mex" binding="mexTcpBinding" contract="IMetadataExchange" />
</service>
</services>
从 WCF SOAP 应用程序调用 WCF Web HTTP 应用程序时,服务将返回以下错误:405 方法不允许
从 WCF 服务调用 WCF Web HTTP 应用程序(使用WebHttpBinding和WebHttpBehavior的服务)时,可能会生成以下异常:Unhandled Exception: System.ServiceModel.FaultException`1[System.ServiceModel.ExceptionDetail]: The remote server returned an unexpected response: (405) Method Not Allowed.
。发生此异常的原因是 WCF 用传入的OperationContext覆盖了传出的OperationContext。 若要解决此问题,请在 WCF Web HTTP 服务作中创建一个 OperationContextScope 。 例如:
public string Echo(string input)
{
using (new OperationContextScope(this.InnerChannel))
{
return base.Channel.Echo(input);
}
}