防火墙后面的 WCF WebService / IIS 托管和配置问题
Posted
技术标签:
【中文标题】防火墙后面的 WCF WebService / IIS 托管和配置问题【英文标题】:WCF WebService / IIS Hosting & Configuration Issue Behind a Firewall 【发布时间】:2010-10-22 01:02:10 【问题描述】:我有一个简单的 WCF Web 服务。它托管在我们生产域中默认网站下的 IIS 上。 (本地地址:10.10.20.100)
默认情况下,此默认网站设置为端口 80 上的“所有未分配”IP:但是,我注意到这导致 WCF 服务使用服务器本地 DNS 名称生成它的 WSDL。即 wsdl 中的所有 URI 都是
http://myserver.subdomain.domain.com/.../...
这不好,因为我需要将此服务公开给不了解生产环境内部 DNS 的站点。而且这个特定的服务器没有外部 DNS 名称。只是一个外部 IP 地址...
我已经成功地将 IIS 中的设置从“所有未分配”更改为“10.10.20.100”
这会导致服务使用 URI 生成它的 WSDL
http://10.10.20.100/.../...
这对于子域和其他子域中的其他机器来说很好,但是我在这里卡住了。服务器外部 IP 地址 (1.2.3.4) 是通过一些 NAT/PAT 转换映射的,因此它没有在服务器 IP 设置中明确设置(即它不显示在 IP 配置下)
因此,如果我将 IIS 默认网站 IP 地址从“所有未分配”->“1.2.3.4”更改为内部地址,那么 WCF 服务将返回...
错误请求(无效主机名)
如果我在内部 IP 地址上配置 IIS,并尝试通过我得到的外部 IP 地址访问服务
No protocol binding matches the given address
'http://1.2.3.4/TestService/Service.svc'. Protocol bindings are
configured at the Site level in IIS or WAS configuration
有什么方法可以让 IIS/WCF 生成它的 WSDL URI,其外部 IP 地址未在服务器上明确配置?
在我将 WCF 服务从窗口中删除之前,请有人帮助我。
【问题讨论】:
这是个好问题。为什么像这样的问题没有得到支持,而是像“厌倦了编程 GUI/业务应用程序,下一步该做什么?”这样的问题。在几分钟内获得 4 个? 很遗憾,我无法回答您的问题 - 我只能投赞成票。 +1。 感谢到目前为止的答案,伙计们。我今天将通过覆盖 ServiceHost 来尝试 Steve 的建议,如果这不起作用,我将硬着头皮让系统操作员为我们的 API 服务器获取一个新的 FQDN。 这是解决此问题的解决方案***.com/a/9671430 【参考方案1】:这是因为您没有设置主机标头。这似乎是一个非常普遍的问题,我一直遇到它。它生成的 uri 没有配置,它通过检查站点的主机头来查找正确的地址。即使它在虚拟目录中,您也需要转到父目录(在您的情况下为默认目录)并添加主机头。
如果您不知道该怎么做,请告诉我。
【讨论】:
我遇到了同样的问题,这个解决方案已经解决了,但我认为它只影响了 https 主机。也许不吧。我在 IIS 服务器上使用 adsutil.vbs 脚本添加了主机头。它强制 443 端口使用特定的主机名而不是默认主机名。 但是我知道你可以为不安全的绑定设置主机头,所以也许值得一试。 如何添加主机头? technet.microsoft.com/en-us/library/cc753195%28v=ws.10%29.aspx 提供设置主机头的方向【参考方案2】:必须是 IP 地址而不是 FQDN?通过交换到 FQDN 并将其设置在站点的主机标头中,然后通过
绑定到它cscript //nologo %systemdrive%\inetpub\adminscripts\adsutil.vbs set W3SVC/1/ServerBindings ":80:hostname.example.com"
然后回收应用程序池将在生成的 WSDL 中生成该主机名。您会从中受益 - 您可以设置一个内部 DNS 将该 FQDN 解析为内部 IP,以及一个外部 DNS 解析为您的防火墙 IP,然后相同的系统将无需任何更改即可工作。
【讨论】:
【参考方案3】:我也许可以防止忍者暴力...如果我了解您的问题... 您可以手动指定服务应在 web.config 中使用的完整地址,而不是让 ServiceHost 为您计算出来。您必须设置服务的基地址:
<service behaviorConfiguration="Behaviour1" name="Api.Poll">
<endpoint address="soap" binding="basicHttpBinding" bindingConfiguration="soapBinding"
contract="Api.IPoll" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://www.mydomain.com/Api" />
<add baseAddress="http://10.10.20.30/Api" />
</baseAddresses>
</host>
</service>
使用此方法,您的服务应接受指定的基地址,加上服务名称,如果您有额外的端点地址,则应接受。此外,您需要使用自定义 ServiceHostFactory 以编程方式设置基地址。见下文:
public class ServiceHostFactory : System.ServiceModel.Activation.ServiceHostFactory
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
ServiceHost host;
host = new ServiceHost(serviceType, baseAddresses[0]);
return host;
最后,一旦您构建了 ServiceHostFactory 类,您必须通过编辑 .svc 文件中的标记将其连接到您的服务:
<%@ ServiceHost Language="C#" Debug="true" Service="Api.Poll" Factory="Api.ServiceHostFactory" CodeBehind="Poll.svc.cs" %>
【讨论】:
在 IIS 下托管时,web.config 的 BaseAddress 部分将被完全忽略。存在与否没有区别。 IIS 根据虚拟目录配置计算出地址。 ***.com/questions/56249/… 嗯...我以前在 IIS 下使用过它,但这是一个不同的场景,有多个基地址。我想知道您是否可以使用 ServiceHostFactory 以编程方式设置基地址。请参阅修改后的答案。 为这位史蒂夫干杯...这里是格林威治标准时间晚上 9 点,所以我会在我回到办公室并明天再来找你时试一试。你能澄清一下我在哪里创建这个类吗?我是否只需将其放入 App_Code 文件夹,然后让我的服务扩展它? 是的,你可以把它放在 App_Code 部分,这样就可以了。不过,还有最后一步将其连接起来,为此您必须修改 .svc 文件的标记。我已经更新了答案以包含它。【参考方案4】:以下是在 IIS7 中更改标头的方法。如果有帮助,也可以把我的 web.config 放一些。
http://www.sslshopper.com/article-ssl-host-headers-in-iis-7.html
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
<customErrors mode="Off"></customErrors>
</system.web>
<system.serviceModel>
<client/>
<services>
<service name="WcfService1.Service1"
behaviorConfiguration="MyServiceTypeBehaviors">
<host>
<baseAddresses>
<add baseAddress="https://pws.sjukra.is/"/>
</baseAddresses>
</host>
<endpoint address="https://pws.sjukra.is/Service1.svc"
listenUri="/"
binding="wsHttpBinding"
contract="WcfService1.IService1"
bindingConfiguration="myBasicHttpBindingConfig"/>
<endpoint contract="IMetadataExchange"
binding="mexHttpsBinding"
address="mex"/>
</service>
</services>
<bindings>
<wsHttpBinding>
<binding name="myBasicHttpBindingConfig">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="Windows" />
<message clientCredentialType="UserName"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="MyServiceTypeBehaviors">
<serviceMetadata httpsGetEnabled="true"/>
<serviceDebug httpsHelpPageEnabled="true" includeExceptionDetailInFaults="true"/>
<serviceCredentials type="System.ServiceModel.Description.ServiceCredentials">
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="WcfService1.Service1,WcfService1"/>
<serviceCertificate findValue="pws.sjukra.is" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
<clientCertificate>
<authentication certificateValidationMode="ChainTrust" revocationMode="NoCheck"/>
</clientCertificate>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true"></serviceHostingEnvironment>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
【讨论】:
【参考方案5】:尽管这是一个旧线程,但它实际上帮助我将一个项目从 VS Web Developer Express 迁移到包含 WCF 服务的 MonoDevelop。
Web 应用程序使用以下 URL 请求 WCF 服务定义的 javascript 接口:http://127.0.0.1:8080/path-to-service/service.svc/js,这给了我错误:没有协议绑定与给定地址匹配
受此线程的启发,我能够解决问题,因为使用 localhost 而不是 127.0.0.1 访问服务有效!通过对http://localhost:8080/path-to-service/service.svc/js 的请求,我得到了 JavaScript 接口。
实际上我的应用程序没有使用绝对 URL 来包含 JavaScript 接口,但是默认情况下,当从 MonoDevelop 启动应用程序时,它会使用 127.0.0.1 访问应用程序,因此从服务中调用包含 JavaScript 失败。
它仍然不完美,因为我无法使用 localhost 而不是 127.0.0.1 从 MonoDevelop 启动应用程序,因为 XSP 的配置只允许我指定 IP 地址,但至少我知道如何获取围绕它。
【讨论】:
【参考方案6】:问题是,在更改端口或 IP 地址后,您需要重新启动您使用的应用程序池,因为它仍然拥有旧信息,直到它被回收。
【讨论】:
以上是关于防火墙后面的 WCF WebService / IIS 托管和配置问题的主要内容,如果未能解决你的问题,请参考以下文章
从 iOS 目标调用方法 webService (WCF) C)