9

我们有一个托管在 ServerA 上的 WCF 服务,它是一个不能直接访问 Internet 的服务器,并且有一个不可 Internet 路由的 IP 地址。

该服务的前端是 BIGIP,它处理 SSL 加密和解密,并将未加密的请求转发到特定端口上的 ServerA(目前它实际上不做任何负载平衡,但将来可能会添加)。

这意味着我们的客户将通过https://www.OurDomain.com/ServiceUrl调用服务,并通过 BIGIP 设备在http://SeverA:85/ServiceUrl上访问我们的服务;

当我们浏览到发布在https://www.OurDomain.com/ServiceUrl上的 WSDL 时,WSDL 中包含的所有地址都基于http://SeverA:85/ServiceUrl基地址

我们发现我们可以使用主机头设置来设置域,但我们的问题是虽然这会整理域,但我们仍然会使用错误的方案——它会使用http://www.OurDomain.com /ServiceUrl而我们需要它是 Https。

此外,由于我们在该服务器上托管了其他服务(基于 asmx),因此我们在设置主机标头时遇到了一些问题,因此我们认为我们可以在服务器上创建另一个站点(例如,使用端口 82)并设置主机头;现在,除了 http/https 问题之外,我们还有一个问题,因为 WSDL 包含所有 url 中的端口号,BigIP 在端口 443 上工作(用于 SSL)

有没有比实现 Host Headers 更灵活的解决方案?理想情况下,我们需要保持灵活性和易于支持。

感谢您的帮助……</p>

4

5 回答 5

6

This is essentially a multi-part problem that involves a number of discrete solutions to provide the full answer. Essentially there are 3 problems with sitting behind the F5.

  1. The advertised service endpoint hostname.
  2. Hostname of links to xsd:import'ed schemas that describe the data contract
  3. the http/https problem you describe.

Changing the host headers, as you have found solves 1 and 2 (you can approach this in ways other than host headers, but no need to go into that here). Number 3 is a bit more tricky and requires more code (too much to dump out here).

The short answer is that you need to write a ContractBehavior that implements both IContractBehavior and IWsdlExportExtension.

The important bit you need to implement is the IWsdlExportExtension.ExportEndpoint. Within this method you need to iterate over all the WsdlPort Extensions, and when you find an extension that is of type SoapAddressBinding you need to replace the SoapAddressBinding.Location property with a new Uri that contains the https protocol specifier. You also need to do similar bits for the xsd import addresses and schema links.

If your service is also using WS-Addressing You then need to do something similar to handle the additional addresses it writes out to the wsdl.

I based the code I ended up writing on the WsdlExtras project available on CodePlex (http://wcfextras.codeplex.com/). The method used in the WsdlExtras provides a great base for any extra bits you may need to add to it (From memory I don't think it dealt with the WS-Addressing bits). The bit you want to look at is the "Override SOAP Address Location URL".

于 2009-04-17T13:49:49.390 回答
1

Thanks to Mark Allanson, I had exactly the same scenario as yossi dahan had, The WCFExtras.dll file worked for me,

step1. download the WCFExtras.dll (http://www.codeplex.com/WCFExtras/).
step2. add it's reference to your project.
step3. don't waste your time in writing any code as suggested in the sample server app.
step4. open the web.config and put the below code:

  <system.net>
     <settings>
        <httpWebRequest useUnsafeHeaderParsing="true" />
     </settings>
  </system.net>


<system.serviceModel>
<services>
  <service behaviorConfiguration="ServiceBehaviorName" name="ServiceName">
    <endpoint address="" behaviorConfiguration="ServiceEndpointBehaviorName" binding="basicHttpBinding" contract="IServiceName">
      <identity>
        <dns value="localhost" />
      </identity>
    </endpoint>
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
  </service>
</services>
<behaviors>
  <endpointBehaviors>
    <behavior name="ServiceEndpointBehaviorName">
      <wsdlExtensions location="https://sslLoadBalancer/ServiceName.svc"/>
    </behavior>
  </endpointBehaviors>
  <serviceBehaviors>
    <behavior name="ServiceBehaviorName">
      <serviceMetadata httpGetEnabled="true" />
      <serviceDebug includeExceptionDetailInFaults="true" />
    </behavior>
  </serviceBehaviors>
</behaviors>
<extensions>
  <behaviorExtensions>
    <!-- Declare that we have an extension called WSDL Extras-->
    <add name="wsdlExtensions" type="WCFExtras.Wsdl.WsdlExtensionsConfig, WCFExtras, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
  </behaviorExtensions>
</extensions>
        </system.serviceModel>


step5. also important to note that if you add reference by this URL "https://sslLoadBalancer/ServiceName.svc" then it will not work, always remember to add reference as: "https://sslLoadBalancer/ServiceName.svc?wsdl" this way you will be able to add reference to your application.

Thats it... if still not works then let me know, I will paste the full web.config file..

Thanks

于 2013-11-21T10:21:40.417 回答
0

如果您在现有服务之上添加 SSL,它可能还会影响 WCF 客户端的绑定安全模式,您可以轻松覆盖该模式。

对于 WSDL,您为什么不直接下载文件,将 URL 更改为您想要的任何内容,然后手动将它们发布为文件?

于 2009-03-28T05:57:42.033 回答
0

I got a great tip that setting the address attribute on the endpoint to the url you wish to display in the WSDL and then add a listenUri attribute to the endpoint with the actual Uri to listen on would do the trick.

The Url in the test page does not get affected (i.e it will still show the address specified in the ListenUri) but within the WSDL the correct Uri will be set (the one specified in the address.

Most annoyingly, though - when I tried this shortly after I posted the question, I could not get it to work within IIS, only when self hosting in a console app; checking myself today I found that it does indeed work; so now I'm not sure why it didn't work for me before;

What we have done in the mean time is buid a simple custom behaviour that changed the service description putting the address required in the WSDL from configurtion; obviously if there's built in support for that it's much better, so I will hopfully get some time next week to look into this further.

于 2009-03-30T13:16:52.913 回答
0

To your service class add the attribute:

<ServiceBehavior(AddressFilterMode:=AddressFilterMode.Any)>

This allows the service to be addressed by the client as https://... but the service to be hosted on http://.....

In the web.config of the service host, the endpoint element must have an absolute URL in the address attribute that is the public URL that will be used by the client. In the same endpoint element, set the listenUri attribute to the absolute URL on which the service host is listening. The way I determine what the default absolute URI the host is listening on is is to add a service reference in a client application which points the the physical server where the service is hosted. The web.config of the client will have an address for the service. I then copy that into the listenUri attribute in the hosts web.config.

In your service behavior configuration add the element serviceMetaData with attribute httpGetEnabled=true

So you'll have something like:

<serviceBehaviors>
  <behavior name="myBehavior">
    <serviceMetadata httpGetEnabled="true" />
  </behavior
</serviceBehaviors>
...
<services>
  <service name="NamespaceQualifiedServiceClass" behavior="myBehavior" >
    <endpoint address="https://www.sslloadbalancer.com" binding="someBinding" contract="IMyServiceInterface" listenUri="http://www.servicehost.com" ...  />
  </service>
</services>

I am not sure if this works with message security or transport security. For this particular application, the credentials were passed as part of the DataContract so we had basicHttpBinding security mode = none. Since the transport is secure (to the ssl load balancer) there were no security issues.

It is also possible in to leave the listenUri attribute blank, however it must be present.

Unfortunately, there is a bug in WCF where the the base address of imported schemas in the WSDL have the listenUri base address rather than the public base address (the one configured using the address attribute of the endpoint). To work around that issue, you need to create an IWsdlExportExtension implementation which brings the imported schemas into the WSDL document directly and removes the imports. An example of this is provided here http://winterdom.com/2006/10/inlinexsdinwsdlwithwcf. Additionally you can have the example class inherit from BehaviorExtensionElement and complete the two new methods with:

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

This will allow you to add an extension behavior in the .config file and add the behavior using configuration rather than having to create a service factory.

under the system.servicemodel configuration element add:

  <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>

And then reference the new endpoint behavior in your endpoint configuration using the behaviorConfiguration attribute

<endpoint address="" binding="basicHttpBinding" contract="WCFWsdlFlatten.IService1" behaviorConfiguration="SSLLoadBalancerBehavior">
于 2009-06-02T16:08:42.177 回答