【发布时间】:2015-05-20 09:01:22
【问题描述】:
我开发了一个 WCF 双工服务和一个 Windows Winforms 客户端通过 net.tcp 双工绑定进行通信。
两者都可以在我的 LAN 上进行通信和正常工作,WCF 服务托管在 Windows 8 工作站上的 IIS 7 上。
然后,我尝试在运行 Windows server 2008 R2 的租用专用服务器上托管 Web 上的 WCF 服务,该服务器具有固定 IP 地址:(94.23.220.199),运行 IIS 7 和 .Net 4.5.2。
WCF 服务已安装在 /ScgBroadcastorService 虚拟路径上,并且 net.tcp 协议已激活。 (实际上,所有 IIS 配置内容都与我 LAN 上的个人 IIS 完全一样)。因此,应该可以通过以下 URL 从外部访问该服务:“http://94.23.220.199/ScgBroadcastorService/Service.svc”。
如果您从浏览器访问此链接,您将获得一个正确的“ScgBroadcastorService 服务”页面,其中包含两个 wsdl 链接。 (这些链接正确引用了“94.23.220.199”IP 地址。
如果单击此链接,则可以正确获取 wsdl xml 文档。
所以由于可以从外部访问 wsdl 文档,我希望客户端能够与 WCF 服务进行通信..
但是,如果我启动客户端,我会收到以下异常:(对不起,我的家用计算机已本地化为法语......根异常是“服务器拒绝了客户端凭据。”)
这是完整的跟踪:
System.ServiceModel.Security.SecurityNegotiationException: Le serveur a rejeté les informations d'identification du client. ---> System.Security.Authentication.InvalidCredentialException: Le serveur a rejeté les informations d'identification du client. ---> System.ComponentModel.Win32Exception: La tentative d’ouverture de session a échoué
--- Fin de la trace de la pile d'exception interne ---
à System.Net.Security.NegoState.ProcessReceivedBlob(Byte[] message, LazyAsyncResult lazyResult)
à System.Net.Security.NegoState.StartReceiveBlob(LazyAsyncResult lazyResult)
à System.Net.Security.NegoState.CheckCompletionBeforeNextReceive(LazyAsyncResult lazyResult)
à System.Net.Security.NegoState.StartSendBlob(Byte[] message, LazyAsyncResult lazyResult)
à System.Net.Security.NegoState.CheckCompletionBeforeNextSend(Byte[] message, LazyAsyncResult lazyResult)
à System.Net.Security.NegoState.ProcessReceivedBlob(Byte[] message, LazyAsyncResult lazyResult)
à System.Net.Security.NegoState.StartReceiveBlob(LazyAsyncResult lazyResult)
à System.Net.Security.NegoState.CheckCompletionBeforeNextReceive(LazyAsyncResult lazyResult)
à System.Net.Security.NegoState.StartSendBlob(Byte[] message, LazyAsyncResult lazyResult)
à System.Net.Security.NegoState.ProcessAuthentication(LazyAsyncResult lazyResult)
à System.Net.Security.NegotiateStream.AuthenticateAsClient(NetworkCredential credential, ChannelBinding binding, String targetName, ProtectionLevel requiredProtectionLevel, TokenImpersonationLevel allowedImpersonationLevel)
à System.Net.Security.NegotiateStream.AuthenticateAsClient(NetworkCredential credential, String targetName, ProtectionLevel requiredProtectionLevel, TokenImpersonationLevel allowedImpersonationLevel)
à System.ServiceModel.Channels.WindowsStreamSecurityUpgradeProvider.WindowsStreamSecurityUpgradeInitiator.OnInitiateUpgrade(Stream stream, SecurityMessageProperty& remoteSecurity)
--- Fin de la trace de la pile d'exception interne ---
Server stack trace:
à System.ServiceModel.Channels.WindowsStreamSecurityUpgradeProvider.WindowsStreamSecurityUpgradeInitiator.OnInitiateUpgrade(Stream stream, SecurityMessageProperty& remoteSecurity)
à System.ServiceModel.Channels.StreamSecurityUpgradeInitiatorBase.InitiateUpgrade(Stream stream)
à System.ServiceModel.Channels.ConnectionUpgradeHelper.InitiateUpgrade(StreamUpgradeInitiator upgradeInitiator, IConnection& connection, ClientFramingDecoder decoder, IDefaultCommunicationTimeouts defaultTimeouts, TimeoutHelper& timeoutHelper)
à System.ServiceModel.Channels.ClientFramingDuplexSessionChannel.SendPreamble(IConnection connection, ArraySegment`1 preamble, TimeoutHelper& timeoutHelper)
à System.ServiceModel.Channels.ClientFramingDuplexSessionChannel.DuplexConnectionPoolHelper.AcceptPooledConnection(IConnection connection, TimeoutHelper& timeoutHelper)
à System.ServiceModel.Channels.ConnectionPoolHelper.EstablishConnection(TimeSpan timeout)
à System.ServiceModel.Channels.ClientFramingDuplexSessionChannel.OnOpen(TimeSpan timeout)
à System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
à System.ServiceModel.Channels.ServiceChannel.OnOpen(TimeSpan timeout)
à System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
à System.ServiceModel.Channels.ServiceChannel.CallOpenOnce.System.ServiceModel.Channels.ServiceChannel.ICallOnce.Call(ServiceChannel channel, TimeSpan timeout)
à System.ServiceModel.Channels.ServiceChannel.CallOnceManager.CallOnce(TimeSpan timeout, CallOnceManager cascade)
à System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
à System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
à System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
请注意,如果我直接从主机启动客户端,使用相同的客户端配置文件,客户端可以完美连接和通信!
这是当前安装在托管服务的服务器上的 web.config 文件:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" />
</system.web>
<system.serviceModel>
<services>
<service name="ScgServiceLibrary.ScgBroadcastorService">
<endpoint binding="netTcpBinding" contract="ScgServiceLibrary.IScgBroadcastorService">
<identity>
<servicePrincipalName value="host/94.23.220.199" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="True" httpsGetEnabled="True"/>
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
</configuration>
这是我从外部和主机使用的客户端配置文件:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="NetTcpBinding_IScgBroadcastorService">
<security mode="None"></security>
</binding>
</netTcpBinding>
</bindings>
<client>
<endpoint address="net.tcp://94.23.220.199/ScgBroadcastorService/Service.svc"
binding="netTcpBinding" bindingConfiguration="NetTcpBinding_IScgBroadcastorService"
contract="ScgServiceLibrary.IScgBroadcastorService" name="NetTcpBinding_IScgBroadcastorService">
<identity>
<servicePrincipalName value="host/94.23.220.199" />
</identity>
</endpoint>
</client>
</system.serviceModel>
</configuration>
注意我已经添加了
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
服务器上 web.config 文件末尾的行,以获取一个服务页面,其中包含两个 wsdl 链接上的 IP 地址。如果没有这一行,两个链接包括计算机名“ns304385”而不是 IP 地址,当然 wsdl 无法从外部获取。
感谢您帮助 mo 解决剩余的部署问题。我现在陷入困境,不知道该怎么做才能让我的客户访问我托管在网络上的 WCF 服务...
【问题讨论】:
-
是否在 IIS 中的网站上激活了 net.tcp 绑定 (808:*)?很确定 Net.Tcp 侦听器适配器 WPA 的 Windows 服务也需要运行
-
我已经在 IIS 中托管的 ScgBroadcastorService 应用程序的高级设置中激活了 net.tcp 协议。你是这个意思吗?
-
是的,“net.tcp 侦听器适配器”服务正在运行。
-
不完全。虽然您在 Advanced Settings.Enabled Protocols 中有“net.tcp”,但最终 net.tcp 必须出现在
web site node的 Bindings 中,例如选择“默认网站”;然后单击绑定...。也检查一下,谢谢 -
是的,我刚刚检查了这个。 net.tcp 协议出现在我的默认网站的绑定设置中(808.*)...