公共反向代理背后的 WCF Webservice
Posted
技术标签:
【中文标题】公共反向代理背后的 WCF Webservice【英文标题】:WCF Webservice behind public reverse proxy 【发布时间】:2010-09-21 11:00:26 【问题描述】:如何从侦听公共 IP 的反向代理后面正确地提供位于专用 LAN 中的 WCF Web 服务的 WSDL?
我有一个配置为反向代理模式的 Apache 网络服务器,它侦听公共 IP 地址上的请求并从内部 IIS 主机为它们提供服务。 WCF Web 服务使用 LAN 主机的 FQDN 地址生成 WSDL,当然,互联网 Web 服务客户端无法读取该地址。
是否可以在 wcf 应用程序的 web.config 或 IIS 中配置任何设置,以自定义生成的包含主机地址的 WSDL 并放置公共地址?
【问题讨论】:
【参考方案1】:将以下属性添加到您的服务类:
<ServiceBehavior(AddressFilterMode:=AddressFilterMode.Any)>
这允许客户端将服务寻址为https://...
,但该服务仍可以托管在http://.....
上
请参阅我在 How to specify AddressFilterMode.Any declaratively 上的回答,了解如何创建扩展以允许通过配置指定 AddressFilterMode.Any
而无需代码属性。
在服务主机的web.config
中,端点元素必须在地址属性中有一个绝对URL,即客户端将使用的公共URL。在同一端点元素中,将listenUri
属性设置为服务主机正在侦听的绝对 URL。
我确定主机正在侦听的默认绝对 URI 的方法是在客户端应用程序中添加一个服务引用,该引用指向托管服务的物理服务器。客户端的 web.config 将包含服务的地址。然后我将其复制到主机 web.config 中的 listenUri 属性中。
在您的服务行为配置中,添加属性为httpGetEnabled=true
的元素serviceMetaData
所以你会有这样的东西:
<serviceBehaviors>
<behavior name="myBehavior">
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
<!-- ... -->
<services>
<service name="NamespaceQualifiedServiceClass" behavior="myBehavior" >
<endpoint listenUri="http://www.servicehost.com"
address="https://www.sslloadbalancer.com"
binding="someBinding"
contract="IMyServiceInterface" ... />
</service>
</services>
我不确定这是否适用于消息安全或传输安全。对于这个特定的应用程序,凭据作为 DataContract 的一部分传递,所以我们有 basicHttpBinding
> security
> mode=none
。由于传输是安全的(对于 ssl 负载平衡器),因此不存在安全问题。
也可以将listenUri 属性留空,但它必须存在。
不幸的是,WCF 中存在一个错误,其中 WSDL 中导入架构的基地址具有 listenUri 基地址而不是公共基地址(使用端点的地址属性配置的基地址)。要解决这个问题,您需要创建一个 IWsdlExportExtension 实现,它将导入的模式直接引入 WSDL 文档并删除导入。
Inline XSD in WSDL with WCF 上的这篇文章中提供了一个示例。此外,您可以让示例类继承自 BehaviorExtensionElement
,并通过以下方式完成两个新方法:
Public Overrides ReadOnly Property BehaviorType() As System.Type
Get
Return GetType(InlineXsdInWsdlBehavior)
End Get
End Property
Protected Overrides Function CreateBehavior() As Object
Return New InlineXsdInWsdlBehavior()
End Function
这将允许您在 .config 文件中添加扩展行为,并使用配置添加行为,而不必创建服务工厂。
在system.servicemodel
配置元素下添加:
<behaviors>
<endpointBehaviors>
<behavior name="SSLLoadBalancerBehavior">
<flattenXsdImports/>
</behavior>
</endpointBehaviors>
</behaviors>
<extensions>
<behaviorExtensions>
<!--The full assembly name must be specified in the type attribute as of WCF 3.5sp1-->
<add name="flattenXsdImports" type="Org.ServiceModel.Description.FlattenXsdImportsEndpointBehavior, Org.ServiceModel, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</behaviorExtensions>
</extensions>
然后使用 behaviorConfiguration 属性在端点配置中引用新的端点行为
<endpoint address="" binding="basicHttpBinding" contract="WCFWsdlFlatten.IService1" behaviorConfiguration="SSLLoadBalancerBehavior">
【讨论】:
我只想指出,这个答案是基于 WCF 3.5。我没有机会检查 WCF 4.0 是否纠正了其中一些问题。我确实知道为了更好地支持反向代理场景,我们做了一些改进。 我已经尝试过了,它可以工作,但它有一些问题:你必须将所有类型、合同和绑定放在同一个命名空间中,如果你有类似 FooRequest 的类型'将不得不重命名它们,因为 wcf 将生成具有相同名称的类型。对我来说,手动编辑 wsdl 文件更方便,否则我的服务的用户将不得不更改他们的代码。 @Dutch - 我的解决方案通常有一个业务对象项目和一个服务项目,每个项目都有不同的命名空间(例如 org.app.bo 和 org.app.servicemodel)。来自业务对象的数据被复制到服务对象中,反之亦然。我使用服务项目中定义的接口来定义合同(org.app.servicemodel.ISomeService)。服务方法通常以 org.app.servicemodel.SomethingRequest 类型作为参数,并返回 org.app.servicemodel.SomethingResponse 类型。使用这种类型的设置我没有遇到命名冲突。你在做别的事吗? 最初我为我的消息、合同和绑定使用单独的 xml 命名空间。我都将它们放在同一个命名空间中,因为内联不起作用。在那次更改之后,我遇到了这样的命名冲突:link 好的,现在我明白了其中的区别。我根据阅读过的一些最佳实践文档添加了自己的版本化命名空间。这可能就是为什么我没有遇到使用 SomethingRequest 和 SomethingResponse 类型的问题。请参阅版本控制指南 blogs.msdn.com/b/craigmcmurtry/archive/2006/07/23/676104.aspx 和 msdn.microsoft.com/en-us/library/ms733832.aspx【参考方案2】:我遇到了类似的问题,其中之一是公共地址和服务器地址的解析。这解决了这个问题,尽管我仍然有几个身份验证问题。
见:董文龙How to change HostName in WSDL for an IIS-hosted service?
archive
【讨论】:
天哪,史蒂夫,非常感谢这个链接,过去几个小时我都快疯了。【参考方案3】:见:Service Station WCF Addressing In Depth Aaron Skonnard
archive link
【讨论】:
该内容似乎已移至msdn.microsoft.com/en-us/magazine/cc163412.aspx。以上是关于公共反向代理背后的 WCF Webservice的主要内容,如果未能解决你的问题,请参考以下文章
Nginx 反向代理背后的 Grafana 返回 alert.title