【问题标题】:WCF Webservice behind public reverse proxy公共反向代理背后的 WCF Webservice
【发布时间】: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 并放置公共地址?

【问题讨论】:

    标签: wcf wsdl reverse-proxy


    【解决方案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.aspxmsdn.microsoft.com/en-us/library/ms733832.aspx
    【解决方案2】:

    我遇到了类似的问题,其中之一是公共地址和服务器地址的解析。这解决了这个问题,尽管我仍然有几个身份验证问题。

    :董文龙How to change HostName in WSDL for an IIS-hosted service?

    archive

    【讨论】:

    • 天哪,史蒂夫,非常感谢这个链接,过去几个小时我都快疯了。
    【解决方案3】:

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-03-24
    • 2012-08-23
    • 1970-01-01
    • 2019-03-14
    • 2014-04-24
    • 2017-06-22
    • 1970-01-01
    • 2019-03-14
    相关资源
    最近更新 更多