首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在IIS7中使用net.tcp绑定托管WCF服务(无法从外部访问)

在IIS7中使用net.tcp绑定托管WCF服务(无法从外部访问)
EN

Stack Overflow用户
提问于 2015-05-20 17:01:23
回答 4查看 2.5K关注 0票数 3

我已经开发了一个WCF双工服务和一个通过net.tcp双工绑定与她通信的Windows Winforms客户端。

两者在我的局域网上都能很好地通信和工作,WCF服务托管在Windows 8工作站上的IIS 7上。

然后,我尝试在租用的专用服务器上托管网络上的WCF服务,该服务器运行Windows server2008 R2,具有固定的IP地址:(94.23.220.199),运行IIS7和.Net 4.5.2。

已在/ScgBroadcastorService虚拟路径上安装WCF服务,并且已激活net.tcp协议。(实际上,所有的IIS配置内容都与我在LAN上的个人IIS完全一样)。因此,应该可以通过以下网址从外部访问该服务:"http://94.23.220.199/ScgBroadcastorService/Service.svc“。

如果从浏览器访问此链接,您将获得一个包含两个ScgBroadcastorService链接的正确的“wsdl服务”页面。(这些链接正确地引用了"94.23.220.199“IP地址。

如果单击此链接,就会正确地获得wsdl xml文档。

因此,由于可以从外部访问wsdl文档,因此我希望客户端能够与WCF服务进行通信。

但如果我启动客户端,我会得到以下异常:(对不起,我的家用计算机本地化成了法语……根异常是“服务器拒绝了客户端凭据”。)

下面是完整的跟踪:

代码语言:javascript
复制
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文件:

代码语言:javascript
复制
<?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>

下面是我在外部和主机上使用的客户端配置文件:

代码语言:javascript
复制
<?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>

注意,我已经添加了

代码语言:javascript
复制
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />

在服务器上的web.config文件末尾添加一行代码,以获得包含两个wsdl链接上的IP地址的服务页面。如果没有这一行,两个链接包括计算机名“wsdl”,而不是IP地址,当然也无法从外部获取ns304385。

感谢您帮助mo解决剩余的部署问题..我现在被困住了,不知道该怎么做才能让我的客户访问托管在网上的WCF服务……

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2015-05-21 09:14:38

好吧,我终于在半夜解决了这个问题……

我不得不关掉两边netTcpBinding的安全保护。

但是,对于需要双工通信的合同,要了解如何在服务器端关闭它并不是那么简单。

下面是web.config文件:

代码语言:javascript
复制
<?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“。这是我在客户端的新配置文件:

代码语言:javascript
复制
<?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客户端工作正常,并与我的双工WCF服务进行通信!

我不得不说,解决这个问题真是一场噩梦……

我希望这个问题的完整描述将帮助其他开发人员尝试在网络上托管他们的双工net.Tcp绑定的WCF服务,并在找到正确的方法修改他们的配置文件之前厌倦所有意外的异常。

各位,晚上好!在回去工作前只睡了三个小时。:-(

票数 3
EN

Stack Overflow用户

发布于 2016-07-29 16:40:10

将安全模式设置为" None“不是解决此问题的方法,因为将security设置为None也会删除消息的机密性(加密)和完整性(签名)。

代码语言:javascript
复制
<security mode="None"></security>

要删除身份验证,可以执行以下任一操作: 1)将安全模式设置为消息

代码语言:javascript
复制
<bindings>
    <netTcpBinding>
        <binding name="NetTcpBinding_IScgBroadcastorService">
            <security mode="Message">
                <message clientCredentialType="None" />
            </security>
        </binding>
    </netTcpBinding>
</bindings>

2)或将安全模式设置为传输

代码语言:javascript
复制
<bindings>
    <netTcpBinding>
        <binding name="NetTcpBinding_IScgBroadcastorService">
            <security mode="Transport">
                <transport clientCredentialType="None" />
            </security>
        </binding>
    </netTcpBinding>
</bindings>

我必须承认我没有在你的代码中尝试这样做。我只是想确保阅读本文的人确实知道身份验证和消息安全不是一回事,并将它们引向正确的方向。

票数 0
EN

Stack Overflow用户

发布于 2018-05-31 06:33:24

我在远程机器上的windows服务中托管的双工wcf服务也遇到了同样的错误。要使其正常工作,我必须创建入站和出站规则,以便在Windows防火墙高级设置中打开服务端口。此外,我还创建了一个服务器用户,并在我的客户端中包含了以下代码:

代码语言:javascript
复制
this._client = new WcfService.WcfServiceClient(context);
_client.ClientCredentials.Windows.ClientCredential.UserName = user;
_client.ClientCredentials.Windows.ClientCredential.Password = password;
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30344977

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档