WCF通过SSL连接出现404错误

43

好的,我肯定是在这里错过了某些非常简单的东西,因为我已经搜索了好几天,在那里看了数十个答案,以及在SO和这里看了数十个答案,但无论我尝试什么,我都无法使它工作。当以纯HTTP方式调用服务时,该服务完全正常工作。

这是我们的设置...我们有一个域名,http://www.mydomain.com。我们已经在该域上安装了来自thawte的SSL证书,就像我们在保护电子商务站点时那样。这一切都正常工作,我可以访问 https://www.mydomain.com,并且它可以正常工作。 我正在运行VS2008,.NET 3.5站点,运行在Windows Server 2003 R2上。

现在,我向我的站点添加了一个启用Silverlight的WCF服务,我希望通过SSL与其通信。如果我浏览到https://www.mydomain.com/myservice.svc,它会按预期显示WSDL描述性的“您已创建了一个服务”页面,其中显示要使用以下代码创建客户端:

svcutil.exe https:// ... 

编辑:我意识到WSDL文件中显示的svcutil网址实际上指向Web服务器的物理框名,而不是正确的域名。因此,我按照这篇博客文章中所示的步骤,使用adsutil脚本更新IIS中网站的SecureBinding。现在,wsdl文件显示了正确的SSL地址,但我仍然收到相同的错误。

现在我尝试将我的Silverlight应用程序连接到它,但它不起作用,并在异步调用结果中返回一个异常,声明“远程服务器返回错误:未找到”。许多博客都谈到通过创建测试Windows应用程序来缩小到Silverlight问题,并尝试从那里引用它。嗯,我这样做了,即使在常规Windows应用程序中尝试访问通过SSL的服务时,我也会收到一个异常声明:

System.ServiceModel.EndpointNotFoundException: 
There was no endpoint listening at https://www.mydomain.com/mysubdir/myservice.svc that could accept the message. 
This is often caused by an incorrect address or SOAP action. 
See InnerException, if present, for more details. ---> 
System.Net.WebException: The remote server returned an error: (404) Not Found.
at System.Net.HttpWebRequest.GetResponse()
at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)

尽管我已经使用HTTPS方案将服务引用明确添加到Windows应用程序中,并且它正确获取所有方法并在编辑器中显示它们,但情况仍然如此。

请注意,这是一项不需要用户明确登录的服务。我将在我的SOAP信封中发送自定义标头以验证请求来自我们的应用程序,并且我只想防止窃听者嗅探线路并挑选出自定义标头。

现在进入代码,我可能只是有些愚蠢的小设置错误,因为从我所读的所有内容来看,这应该是一个相当直截了当的练习。

首先,我的服务的代码后台类附有以下属性:

<ServiceBehavior(AddressFilterMode:=AddressFilterMode.Any)> 
<AspNetCompatibilityRequirements(RequirementsMode:=AspNetCompatibilityRequirementsMode.Allowed)>

我的 web.config 文件中的 ServiceModel 部分如下:

<system.serviceModel>
    <bindings>
        <basicHttpBinding>
            <binding name="basicHttpBinding">
                <security mode="Transport">
                    <transport clientCredentialType ="None"/>
                </security>
            </binding>
        </basicHttpBinding>
    </bindings>
    <behaviors>
        <serviceBehaviors>
            <behavior name="standingsBehavior">
                <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
                    <serviceDebug includeExceptionDetailInFaults="false"/>
                </behavior>
            </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true">
        <baseAddressPrefixFilters>
            <add prefix="http://www.mydomain.com:80"/>
        </baseAddressPrefixFilters>
    </serviceHostingEnvironment>
    <services>
        <service behaviorConfiguration="standingsBehavior" name="lijslwebdata">
            <endpoint address="" binding="basicHttpBinding" contract="lijslwebdata"/>
            <!--<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>-->
        </service>
    </services>
</system.serviceModel>

我的 Windows 应用程序的 app.config 中的 ServiceModel 部分如下所示:

<system.serviceModel>
    <bindings>
        <basicHttpBinding>
            <binding name="BasicHttpBinding_lijslwebdata" closeTimeout="00:01:00"
                openTimeout="00:01:00" receiveTimeout="00:10:00" 
                sendTimeout="00:01:00" allowCookies="false" 
                bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
                maxBufferSize="65536" maxBufferPoolSize="524288" 
                maxReceivedMessageSize="65536" messageEncoding="Text" 
                textEncoding="utf-8" transferMode="Buffered"
                useDefaultWebProxy="true">
                <readerQuotas maxDepth="32" maxStringContentLength="8192"
                    maxArrayLength="16384"
                    maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                <security mode="Transport">
                    <transport clientCredentialType="None" proxyCredentialType="None" realm=""/>
                    <message clientCredentialType="UserName" algorithmSuite="Default" />
                </security>
            </binding>
        </basicHttpBinding>
    </bindings>
    <client>
        <endpoint address="https://www.mydomain.com/mysubdir/myservice.svc"
            binding="basicHttpBinding" 
            bindingConfiguration="BasicHttpBinding_lijslwebdata"
            contract="xdata.lijslwebdata" name="BasicHttpBinding_lijslwebdata" />
    </client>
</system.serviceModel>

一个问题,baseAddressPrefixFilters需要以某种方式设置为HTTPS吗? - eidylon
我也非常感兴趣。目前我有一个HTTP WCF服务,提供HTTPS选项时可能会遇到麻烦。请记得发布你的结果! :) - Program.X
10个回答

30

我也遇到了同样的问题。你的帖子帮助我找出了问题所在。这是我的服务模型部分。我发现关键是httpsGetEnabled,然后设置bindingconfiguration。希望这可以帮到你。

<system.serviceModel>
        <behaviors>
            <serviceBehaviors>
                <behavior name="RequestImageBehavior">
                    <serviceMetadata **httpsGetEnabled**="true" />
                    <serviceDebug includeExceptionDetailInFaults="false" />
                  <dataContractSerializer maxItemsInObjectGraph="1073741824" />
                </behavior>
            </serviceBehaviors>
        </behaviors>
        <services>
            <service behaviorConfiguration="RequestImageBehavior" name="RequestImage">
                <endpoint address="" 
                          binding="wsHttpBinding" 
                          **bindingConfiguration**="HttpsBinding"
                          contract="IRequestImage">
                </endpoint>
                <endpoint address="mex" 
                          binding="mexHttpBinding" 
                          contract="IMetadataExchange" />
            </service>
        </services>
      <bindings>
        **<wsHttpBinding>
          <binding name="HttpsBinding">
            <security mode="Transport">
              <transport clientCredentialType="None"/>
            </security>
          </binding>
        </wsHttpBinding>**
      </bindings>
    </system.serviceModel>

我有同样的问题。我发现我的bindingConfiguration没有设置,但是我的bindingName已经设置了。一旦我设置了binding configuration,事情就开始按照预期工作了。谢谢! - Wil P
1
这对我有用,但我不得不将<wsHttpBinding>重命名为<webHttpBinding> - 可能是.NET版本的差异? - theyetiman
theyetiman,看看这个链接,了解wsHttpBinding和webHttpBinding之间的区别。完全是不同的游戏规则。https://dev59.com/znE85IYBdhLWcg3wtVxT - markwilde

14

最近我也遇到了这个问题,并想要添加一些调整。如果按照上述说明操作,您将能够使服务在HTTPS上工作,但不能同时在HTTP和HTTPS上工作。要做到这一点,您需要有两个端点配置节点,一个用于每种协议,如下所示:

 <service name="MyCompany.MyService" >
    <endpoint address="" behaviorConfiguration="AspNetAjaxBehavior"
      binding="webHttpBinding" contract="MyCompany.MyService" bindingConfiguration="sslBinding" />
    <endpoint address="" behaviorConfiguration="AspNetAjaxBehavior"
      binding="webHttpBinding" contract="MyCompany.MyService" />
  </service>

(来源于我的代码库,根据需要调整behaviorConfiguration和binding)


1
谢谢!我实际上发现我的SSL服务在HTTPS下返回了404错误,没有HTTP端点。添加HTTP端点解决了这个问题。真是荒谬。 - Rocklan

8

我刚刚花了几个小时来解决这个问题,结果发现我的问题是服务名称错误。

<services>
      <service name="TimberMill.Web.Data.LogReceiverService">
        <endpoint binding="basicHttpBinding" bindingConfiguration="basicBinding"
                     contract="NLog.LogReceiverService.ILogReceiverServer" />
      </service>
    </services>

我必须确保与我的*.svc文件中类似的条目完全匹配。

<%@ ServiceHost 
    Language="C#" 
    Debug="true" 
    Service="TimberMill.Web.Data.LogReceiverService, TimberMill.Web"
    Factory="Autofac.Integration.Wcf.AutofacServiceHostFactory, Autofac.Integration.Wcf"
    CodeBehind="LogReceiverService.svc.cs" 
%>

我不确定这是否与我的Autofac使用有关。在纯HTTP下一切都正常工作。但在HTTPS下失败了。

我想是这样,我现在不想通过更详细的测试来打扰任何东西,以免激怒WCF-Config之神并使我的配置再次中断。你的情况可能会有所不同。


1
是的,serviceName已经为我解决了这个问题。 - saille

5
在我的情况下,这些答案都没有帮助到我。
相反,我需要添加一个重复的<binding>部分,该部分没有设置name属性
以下是我服务的web.config文件中适当部分的转储:
<behaviors>
    <serviceBehaviors>
        <behavior name="ServiceBehaviour">
            <serviceMetadata 
                httpsGetEnabled="true" 
                httpsGetUrl="RemoteSyncService.svc"
                httpGetBindingConfiguration="bindingConfig" />
            <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
        <behavior name="">
            <serviceMetadata 
                httpsGetEnabled="true" 
                httpsGetUrl="RemoteSyncService.svc" />
            <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
    </serviceBehaviors>
</behaviors>

<bindings>
  <basicHttpBinding>
    <binding name="bindingConfig" maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" transferMode="Streamed">
        <security mode="Transport">
          <transport clientCredentialType="None"/>
        </security>
      <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647"/>
    </binding>

    <!-- Add binding with EMPTY/MISSING name, see https://forums.iis.net/t/1178173.aspx -->
    <binding maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" transferMode="Streamed">
        <security mode="Transport">
          <transport clientCredentialType="None"/>
        </security>
      <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647"/>
    </binding>
  </basicHttpBinding>
</bindings>

我希望这对某些人在某一天有所帮助。


1
为了验证这篇文章,这是唯一对我有效的建议。 - Peder Rice

3

我曾经遇到同样的问题,花了一天时间才解决。最终以下配置使我成功实现了HTTPS访问。

<system.serviceModel>
    <bindings>
        <basicHttpBinding>
            <binding name="basicHttpBinding">
            </binding>
            <binding name="basicHttpsBinding">
                <security mode="Transport">
                    <transport clientCredentialType ="None"/>
                </security>
            </binding>
        </basicHttpBinding>
    </bindings>
    <behaviors>
        <serviceBehaviors>
            <behavior name="standingsBehavior">
                <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
                <serviceDebug includeExceptionDetailInFaults="false"/>
            </behavior>
        </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true">
        <baseAddressPrefixFilters>
            <add prefix="http://www.mydomain.com/"/>
        </baseAddressPrefixFilters>
    </serviceHostingEnvironment>
    <services>
        <service behaviorConfiguration="standingsBehavior" name="lijslwebdata">
            <endpoint address="" binding="basicHttpBinding" contract="lijslwebdata"/>
            <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
        </service>
        <service behaviorConfiguration="standingsBehavior" name="sslwebdata">
            <endpoint address="" binding="basicHttpBinding" bindingConfiguration="basicHttpsBinding" contract="sslwebdata"/>
            <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
        </service>
    </services>
</system.serviceModel>

1

其中几个答案让我重新配置我的web.config以包含两个端点。最终,我得到了以下的Web.config。

<system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="basicHttpBinding">
        </binding>
        <binding name="basicHttpsBinding">
          <security mode="Transport">
            <transport clientCredentialType ="None"/>
          </security>
        </binding>
      </basicHttpBinding>
    </bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior name="standingsBehavior">
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true">
      <baseAddressPrefixFilters>
        <add prefix="http://www.myhost.com"/>
      </baseAddressPrefixFilters>
    </serviceHostingEnvironment>

    <services>
      <service behaviorConfiguration="standingsBehavior" name="NameSpace.ClassName">
        <endpoint address="" binding="basicHttpBinding" contract="NameSpace.ContractInterfaceName"/>
        <endpoint address="" binding="basicHttpBinding" bindingConfiguration="basicHttpsBinding" contract="NameSpace.ContractInterfaceName"/>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
      </service>
    </services>
  </system.serviceModel>

1

一切似乎都很有效,没有任何明显的错误...

只有一个观察/问题:你的*.svc文件在哪里?

在错误信息中,我看到:

 https://www.mydomain.com/myservice.svc 

你的 *.svc 文件真的在站点顶级虚拟目录中吗?

通常,*.svc 文件位于 IIS 上的虚拟目录中,因此地址应该是类似于:

 https://www.mydomain.com/YourVirtualDirectory/myservice.svc 

当然,你可以将一个ASP.NET应用程序和一个WCF服务*.svc文件部署到IIS的根目录下,但在我的经验中并不常见。
只是一个要检查的小东西.....
马克

1
是的,服务实际上在子目录中。我只是出于安全考虑重命名了路径。我猜我应该在虚假路径中加入一个子目录,但实际上它就在一个子目录中。 - eidylon

1

好的,显然我解决了这个问题,但我完全不知道为什么/如何解决。

这是我所做的:

  • 我添加了一个全新的空Silverlight启用的WCF服务
  • 然后我更新了web.config以反映两个服务
  • 然后我只是将第一个服务的所有内容复制并粘贴到第二个服务中,除了名称之外。

为什么这样就解决了问题,我完全不知道。

对于任何人来说,这是我的新web.config ServiceModel部分,其中包含第二个服务...

<system.serviceModel>
    <bindings>
        <basicHttpBinding>
            <binding name="basicHttpBinding">
            </binding>
            <binding name="basicHttpsBinding">
                <security mode="Transport">
                    <transport clientCredentialType ="None"/>
                </security>
            </binding>
        </basicHttpBinding>
    </bindings>
    <behaviors>
        <serviceBehaviors>
            <behavior name="standingsBehavior">
                <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
                <serviceDebug includeExceptionDetailInFaults="false"/>
            </behavior>
        </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true">
        <baseAddressPrefixFilters>
            <add prefix="http://www.mydomain.com/"/>
        </baseAddressPrefixFilters>
    </serviceHostingEnvironment>
    <services>
        <service behaviorConfiguration="standingsBehavior" name="lijslwebdata">
            <endpoint address="" binding="basicHttpBinding" contract="lijslwebdata"/>
            <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
        </service>
        <service behaviorConfiguration="standingsBehavior" name="sslwebdata">
            <endpoint address="" binding="basicHttpBinding" bindingConfiguration="basicHttpsBinding" contract="sslwebdata"/>
            <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
        </service>
    </services>
</system.serviceModel>

3
这让我感到和其他关于WCF/Silverlight的事情一样害怕。太多变量了。从头开始创建一个新项目,它会“正常工作”。但在现实世界中这不是一个选项!(我以前不得不这样做)。感谢您的回答。 - Program.X
我同意,尽管我的问题不是那么多与Silverlight有关,因为即使是我的测试Windows客户端最初也无法连接。这完全是WCF over SSL的问题。 但我同意...我不喜欢那些自动修复的东西。这是一项很好的技术,但需要更加稳定。 - eidylon

1
之前它没有为您工作,因为您将basicHttpBinding配置命名为basicHttpBinding,但在<service>标记中未引用该配置,也未使用bindingConfiguration="basicHttpBinding"
在您添加另一个服务配置的更改中,您引用了包含<security>节点的绑定配置,从而使其工作。

0

如果你遇到了与 OP 相同的 404 错误,请检查另一件事情。我尝试了很多方法,但最终的解决方案只是在我的服务 web.config 中添加命名空间。

所以普通的 ServiceFoo 和 IServiceFoo 并不起作用:

  <services>
     <service behaviorConfiguration="quuxBehavior" name="ServiceFoo">
        <endpoint address="" binding="basicHttpBinding" bindingConfiguration="basicHttpsBinding" contract="IServiceFoo"/>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
     </service>
  </services>

但是添加命名空间(ProjectBar)确实起作用:

  <services>
     <service behaviorConfiguration="quuxBehavior" name="ProjectBar.ServiceFoo">
        <endpoint address="" binding="basicHttpBinding" bindingConfiguration="basicHttpsBinding" contract="ProjectBar.IServiceFoo"/>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
     </service>
  </services>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接