WCF, Metadata y BIGIP: ¿puedo forzar la URL correcta para los elementos WSDL?

StackOverflow https://stackoverflow.com/questions/634522

  •  10-07-2019
  •  | 
  •  

Pregunta

Tenemos un servicio WCF alojado en el Servidor A, que es un servidor con acceso a Internet no directo y tiene una dirección IP enrutable que no es de Internet.

El servicio está liderado por BIGIP, que maneja el cifrado y descifrado SSL y reenvía la solicitud no cifrada al ServidorA (en este momento NO realiza ningún equilibrio de carga, pero es probable que se agregue en el futuro) en un puerto específico .

Lo que eso significa es que nuestros clientes llamarían al servicio a través de https://www.OurDomain.com/ServiceUrl y llegaría a nuestro servicio en http: // SeverA: 85 / ServiceUrl a través del dispositivo BIGIP;

Cuando navegamos hasta el WSDL publicado en https://www.OurDomain.com/ServiceUrl all las direcciones contenidas en el WSDL se basan en la http: // SeverA: 85 / ServiceUrl dirección base

Descubrimos que podíamos usar la configuración de encabezados de host para establecer el dominio, pero nuestro problema es que, si bien esto resolvería el dominio, seguiríamos usando el esquema incorrecto & # 8211; usaría http://www.OurDomain.com/ServiceUrl mientras necesitamos que sea Https.

También & # 8211; Como tenemos otros servicios (basados ??en asmx) alojados en ese servidor, tuvimos algunos problemas para configurar los encabezados del host, por lo que pensamos que podríamos evitar crear otro sitio en el servidor (usando, digamos, el puerto 82) y establecer el encabezado del host en ese; ahora, además del problema http / https, tenemos un problema ya que el WSDL contiene el número de puerto en todas las direcciones URL, donde BigIP funciona en el puerto 443 (para el SSL)

¿Existe una solución más flexible que implementar encabezados de host? Idealmente, debemos mantener la flexibilidad y la facilidad de soporte.

Gracias por cualquier ayuda & # 8230;

¿Fue útil?

Solución

Este es esencialmente un problema de varias partes que involucra una serie de soluciones discretas para proporcionar la respuesta completa. Esencialmente hay 3 problemas al sentarse detrás del F5.

  1. El nombre de host del punto final del servicio anunciado.
  2. Nombre de host de enlaces a xsd: esquemas importados que describen el contrato de datos
  3. el problema http / https que describe.

Cambiando los encabezados del host, como ha encontrado resuelve 1 y 2 (puede abordar esto de otras maneras que no sean los encabezados del host, pero no es necesario entrar en eso aquí). El número 3 es un poco más complicado y requiere más código (demasiado para descargar aquí).

La respuesta breve es que necesita escribir un ContractBehavior que implemente tanto IContractBehavior como IWsdlExportExtension.

El bit importante que necesita implementar es IWsdlExportExtension.ExportEndpoint. Dentro de este método, debe iterar sobre todas las extensiones WsdlPort, y cuando encuentre una extensión que sea del tipo SoapAddressBinding, deberá reemplazar la propiedad SoapAddressBinding.Location con un nuevo Uri que contenga el especificador de protocolo https. También debe hacer bits similares para las direcciones de importación xsd y los enlaces de esquema.

Si su servicio también está utilizando WS-Addressing, entonces debe hacer algo similar para manejar las direcciones adicionales que escribe en el wsdl.

Basé el código que terminé escribiendo en el proyecto WsdlExtras disponible en CodePlex ( http: // wcfextras. codeplex.com/ ). El método utilizado en WsdlExtras proporciona una excelente base para cualquier bit adicional que necesite agregarle (de memoria no creo que haya tratado con los bits de WS-Addressing). La parte que desea ver es la "Anulación de URL de ubicación de dirección SOAP".

Otros consejos

Gracias a Mark Allanson, tuve exactamente el mismo escenario que tenía Yossi Dahan, el archivo WCFExtras.dll funcionó para mí,

paso1. descargue WCFExtras.dll (http://www.codeplex.com/WCFExtras/) .
paso 2. agregue su referencia a su proyecto.
paso 3. no pierda su tiempo escribiendo ningún código como se sugiere en la aplicación de servidor de muestra.
etapa 4. abra el web.config y ponga el siguiente código:

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


paso5. También es importante tener en cuenta que si agrega referencia por esta URL " https: //sslLoadBalancer/ServiceName.svc" entonces no funcionará, recuerde siempre agregar la referencia como: " https : //sslLoadBalancer/ServiceName.svc? wsdl " de esta manera podrá agregar referencias a su aplicación.

Eso es todo ... si aún no funciona, hágamelo saber, pegaré el archivo web.config completo ...

Gracias

Si agrega SSL encima del servicio existente, probablemente también afectaría el modo de seguridad del enlace para el cliente WCF, que puede anular fácilmente.

Para WSDL, ¿por qué no solo descarga los archivos, cambia la URL a lo que quiera y los publica manualmente como archivos?

Recibí un gran consejo de que establecer el atributo de dirección en el punto final a la url que desea mostrar en el WSDL y luego agregar un atributo listenUri al punto final con el Uri real para escuchar sería el truco.

La URL en la página de prueba no se ve afectada (es decir, todavía mostrará la dirección especificada en ListenUri) pero dentro del WSDL se establecerá la Uri correcta (la especificada en la dirección.

Sin embargo, lo más molesto es que cuando intenté esto poco después de publicar la pregunta, no pude hacer que funcionara dentro de IIS, solo cuando me alojé en una aplicación de consola; comprobándome hoy mismo, descubrí que sí funciona; así que ahora no estoy seguro de por qué no me funcionó antes;

Mientras tanto, lo que hemos hecho es crear un comportamiento personalizado simple que cambió la descripción del servicio, poniendo la dirección requerida en el WSDL desde la configuración; obviamente, si hay soporte incorporado para eso, es mucho mejor, así que espero tener algo de tiempo la próxima semana para investigar esto más a fondo.

A su clase de servicio agregue el atributo:

<ServiceBehavior(AddressFilterMode:=AddressFilterMode.Any)>

Esto permite que el cliente aborde el servicio como https: // ... pero el servicio se aloje en http: // .....

En el archivo web.config del host del servicio, el elemento de punto final debe tener una URL absoluta en el atributo de dirección que es la URL pública que utilizará el cliente. En el mismo elemento de punto final, establezca el atributo listenUri en la URL absoluta en la que escucha el host del servicio. La forma en que determino cuál es el URI absoluto predeterminado que escucha el host es agregar una referencia de servicio en una aplicación cliente que apunte al servidor físico donde está alojado el servicio. El web.config del cliente tendrá una dirección para el servicio. Luego copio eso en el atributo listenUri en los hosts web.config.

En su configuración de comportamiento de servicio, agregue el elemento serviceMetaData con el atributo httpGetEnabled = true

Entonces tendrás algo como:

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

No estoy seguro de si esto funciona con seguridad de mensajes o seguridad de transporte. Para esta aplicación en particular, las credenciales se pasaron como parte del DataContract, por lo que teníamos el modo de seguridad basicHttpBinding = none. Dado que el transporte es seguro (al equilibrador de carga SSL) no hubo problemas de seguridad.

También es posible dejar en blanco el atributo listenUri, sin embargo, debe estar presente.

Desafortunadamente, hay un error en WCF donde la dirección base de los esquemas importados en el WSDL tiene la dirección base listenUri en lugar de la dirección base pública (la configurada usando el atributo de dirección del punto final). Para solucionar este problema, debe crear una implementación IWsdlExportExtension que traiga los esquemas importados al documento WSDL directamente y elimine las importaciones. Aquí se proporciona un ejemplo de esto http://winterdom.com/2006/10/inlinexsdinwsdlwithwcf . Además, puede hacer que la clase de ejemplo herede de BehaviorExtensionElement y complete los dos nuevos métodos con:

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

Esto le permitirá agregar un comportamiento de extensión en el archivo .config y agregar el comportamiento usando la configuración en lugar de tener que crear una fábrica de servicios.

bajo el elemento de configuración system.servicemodel agregar:

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

Y luego haga referencia al nuevo comportamiento de punto final en su configuración de punto final utilizando el atributo behaviourConfiguration

<endpoint address="" binding="basicHttpBinding" contract="WCFWsdlFlatten.IService1" behaviorConfiguration="SSLLoadBalancerBehavior">
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top