在 IIS 7 中使用 net.tcp 绑定托管 WCF 服务(无法从外部访问)
Hosting a WCF service using net.tcp binding in IIS 7 (unreachable from outside)
我开发了一个 WCF 双工服务和一个 Windows Winforms 客户端通过 net.tcp 双工绑定进行通信。
两者都在我的 LAN 上正常通信和工作,WCF 服务托管在 Windows 8 工作站上的 IIS 7 上。
然后我尝试在租用的专用服务器 运行 Windows 服务器 2008 R2 上托管 WCF 服务,固定 IP 地址:(94.23.220.199) 和 IIS 7 运行 和 .Net 4.5.2。
已在 /ScgBroadcastorService 虚拟路径上安装 WCF 服务,并且已激活 net.tcp 协议。 (实际上,所有 IIS 配置内容都与我在 LAN 上的个人 IIS 完全一样)。因此,该服务应该可以从外部访问 URL:“http://94.23.220.199/ScgBroadcastorService/Service.svc”。
如果您从浏览器访问此 link,您将获得一个包含两个 wsdl link 的正确 "ScgBroadcastorService Service" 页面。 (这些 link 正确地引用了“94.23.220.199”IP 地址。
如果单击此 links,则可以正确获取 wsdl xml 文档。
所以由于wsdl文档可能会被外部访问,所以我希望客户端能够与WCF服务通信..
但是如果我启动客户端,我会得到以下异常:(抱歉,我的家用计算机本地化为法语...根异常是 "The server rejected the client credentials.")
这是完整的轨迹:
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 link 上的 IP 地址。如果没有这一行,两个 link 将包含计算机名 "ns304385" 而不是 IP 地址,当然 wsdl 无法从外部获取。
感谢您帮助 mo 解决剩余的部署问题。我现在陷入困境,不知道该怎么做才能让我的客户访问我在网上托管的 WCF 服务...
哇!我刚刚找到了部分解决方案!
至少解释一下为什么我无法从外部访问 WCF 服务!
所以我尝试在服务器上创建一个帐户,其名称和密码与我在尝试启动客户端时在家用计算机上使用的帐户相同...并且...有效! !
当然你会同意我的看法,这是不可接受的...
我希望我的 WCF 服务能够接受从网上任何地方登录并使用他们自己的用户的客户端连接username/password我不想在意!
因此,搜索以另一种方式继续...如何允许 WCF 客户端连接而无需在我的服务器上创建帐户?
敬请期待...希望很快找到答案...
好吧我终于在半夜解决了这个问题...
我不得不关闭双方的 netTcpBinding 安全性。
但是对于需要双工通信的合同,找出如何在服务器端关闭它并不是那么简单。
这是 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>
<bindings>
<netTcpBinding>
<binding name="customTcpBinding" maxReceivedMessageSize="5242880" maxConnections="10">
<readerQuotas maxDepth="64" maxStringContentLength="5242880" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
<security mode="None"></security>
</binding>
</netTcpBinding>
</bindings>
<services>
<service name="ScgServiceLibrary.ScgBroadcastorService">
<endpoint binding="netTcpBinding" bindingConfiguration="customTcpBinding" 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>
诀窍是添加安全模式设置为 "None" 的 customTcpBinding,并在具有 bindingConfiguration 属性的端点中引用此新绑定。
不确定 customTcpBinding 的所有参数是否都是最佳的,但它们对于双工合同来说是可以的。 (我第一次尝试双工合同被拒绝)
在客户端,我还必须将绑定的安全模式设置为 "None"。这是我在客户端的新配置文件:
<?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>
最后我的 WCF Windows WinForm 客户端工作正常并与我的 Duplex WCF 服务通信!!!
我不得不说解决这个问题真是一场噩梦...
希望对我的问题的完整描述能够帮助其他开发人员尝试在网络上托管他们的双工 net.Tcp 绑定 WCF 服务,并且在找到修改配置文件的正确方法之前厌倦了所有意外异常。
各位晚安!回去工作前只睡了三个小时... :-(
将安全模式设置为 "none" 不是解决此问题的方法,因为将安全模式设置为 None 也会删除消息的机密性(加密)和完整性(签名)。
<security mode="None"></security>
要删除身份验证,您可以:
1) 设置安全模式为message
<bindings>
<netTcpBinding>
<binding name="NetTcpBinding_IScgBroadcastorService">
<security mode="Message">
<message clientCredentialType="None" />
</security>
</binding>
</netTcpBinding>
</bindings>
2) 或将安全模式设置为传输
<bindings>
<netTcpBinding>
<binding name="NetTcpBinding_IScgBroadcastorService">
<security mode="Transport">
<transport clientCredentialType="None" />
</security>
</binding>
</netTcpBinding>
</bindings>
我不得不承认我没有用你的代码尝试过这个。
只是想确保阅读本文的人确实知道身份验证和消息安全性不是一回事,并将它们指向正确的方向。
我在远程计算机上的 windows 服务中托管的双工 wcf 服务遇到了同样的错误。为了让它工作,我必须创建入站和出站规则以在 Windows 防火墙高级设置中打开服务端口。我还创建了一个服务器用户并将此代码包含在我的客户端中:
this._client = new WcfService.WcfServiceClient(context);
_client.ClientCredentials.Windows.ClientCredential.UserName = user;
_client.ClientCredentials.Windows.ClientCredential.Password = password;
我开发了一个 WCF 双工服务和一个 Windows Winforms 客户端通过 net.tcp 双工绑定进行通信。
两者都在我的 LAN 上正常通信和工作,WCF 服务托管在 Windows 8 工作站上的 IIS 7 上。
然后我尝试在租用的专用服务器 运行 Windows 服务器 2008 R2 上托管 WCF 服务,固定 IP 地址:(94.23.220.199) 和 IIS 7 运行 和 .Net 4.5.2。
已在 /ScgBroadcastorService 虚拟路径上安装 WCF 服务,并且已激活 net.tcp 协议。 (实际上,所有 IIS 配置内容都与我在 LAN 上的个人 IIS 完全一样)。因此,该服务应该可以从外部访问 URL:“http://94.23.220.199/ScgBroadcastorService/Service.svc”。
如果您从浏览器访问此 link,您将获得一个包含两个 wsdl link 的正确 "ScgBroadcastorService Service" 页面。 (这些 link 正确地引用了“94.23.220.199”IP 地址。
如果单击此 links,则可以正确获取 wsdl xml 文档。
所以由于wsdl文档可能会被外部访问,所以我希望客户端能够与WCF服务通信..
但是如果我启动客户端,我会得到以下异常:(抱歉,我的家用计算机本地化为法语...根异常是 "The server rejected the client credentials.")
这是完整的轨迹:
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 link 上的 IP 地址。如果没有这一行,两个 link 将包含计算机名 "ns304385" 而不是 IP 地址,当然 wsdl 无法从外部获取。
感谢您帮助 mo 解决剩余的部署问题。我现在陷入困境,不知道该怎么做才能让我的客户访问我在网上托管的 WCF 服务...
哇!我刚刚找到了部分解决方案!
至少解释一下为什么我无法从外部访问 WCF 服务!
所以我尝试在服务器上创建一个帐户,其名称和密码与我在尝试启动客户端时在家用计算机上使用的帐户相同...并且...有效! !
当然你会同意我的看法,这是不可接受的...
我希望我的 WCF 服务能够接受从网上任何地方登录并使用他们自己的用户的客户端连接username/password我不想在意!
因此,搜索以另一种方式继续...如何允许 WCF 客户端连接而无需在我的服务器上创建帐户?
敬请期待...希望很快找到答案...
好吧我终于在半夜解决了这个问题...
我不得不关闭双方的 netTcpBinding 安全性。
但是对于需要双工通信的合同,找出如何在服务器端关闭它并不是那么简单。
这是 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>
<bindings>
<netTcpBinding>
<binding name="customTcpBinding" maxReceivedMessageSize="5242880" maxConnections="10">
<readerQuotas maxDepth="64" maxStringContentLength="5242880" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
<security mode="None"></security>
</binding>
</netTcpBinding>
</bindings>
<services>
<service name="ScgServiceLibrary.ScgBroadcastorService">
<endpoint binding="netTcpBinding" bindingConfiguration="customTcpBinding" 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>
诀窍是添加安全模式设置为 "None" 的 customTcpBinding,并在具有 bindingConfiguration 属性的端点中引用此新绑定。
不确定 customTcpBinding 的所有参数是否都是最佳的,但它们对于双工合同来说是可以的。 (我第一次尝试双工合同被拒绝)
在客户端,我还必须将绑定的安全模式设置为 "None"。这是我在客户端的新配置文件:
<?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>
最后我的 WCF Windows WinForm 客户端工作正常并与我的 Duplex WCF 服务通信!!!
我不得不说解决这个问题真是一场噩梦...
希望对我的问题的完整描述能够帮助其他开发人员尝试在网络上托管他们的双工 net.Tcp 绑定 WCF 服务,并且在找到修改配置文件的正确方法之前厌倦了所有意外异常。
各位晚安!回去工作前只睡了三个小时... :-(
将安全模式设置为 "none" 不是解决此问题的方法,因为将安全模式设置为 None 也会删除消息的机密性(加密)和完整性(签名)。
<security mode="None"></security>
要删除身份验证,您可以: 1) 设置安全模式为message
<bindings>
<netTcpBinding>
<binding name="NetTcpBinding_IScgBroadcastorService">
<security mode="Message">
<message clientCredentialType="None" />
</security>
</binding>
</netTcpBinding>
</bindings>
2) 或将安全模式设置为传输
<bindings>
<netTcpBinding>
<binding name="NetTcpBinding_IScgBroadcastorService">
<security mode="Transport">
<transport clientCredentialType="None" />
</security>
</binding>
</netTcpBinding>
</bindings>
我不得不承认我没有用你的代码尝试过这个。 只是想确保阅读本文的人确实知道身份验证和消息安全性不是一回事,并将它们指向正确的方向。
我在远程计算机上的 windows 服务中托管的双工 wcf 服务遇到了同样的错误。为了让它工作,我必须创建入站和出站规则以在 Windows 防火墙高级设置中打开服务端口。我还创建了一个服务器用户并将此代码包含在我的客户端中:
this._client = new WcfService.WcfServiceClient(context);
_client.ClientCredentials.Windows.ClientCredential.UserName = user;
_client.ClientCredentials.Windows.ClientCredential.Password = password;