2010-03-18 20 views
12

Estoy trabajando en un sistema que proporciona una interfaz de jabón. Uno de los sistemas que van a utilizar la interfaz está codificado en Delphi 7. El servicio web está desarrollado con WCF, enlace HTTP básico, SOAP 1.1.Delphi Soap Envelope y WCF

Si uso SOAP UI (JAVA), el servicio funciona correctamente. Pero Delphi parece hacer cosas especiales aquí;)

Esto es cómo el mensaje se ve como en SOAP de interfaz de usuario:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://services.xxx.de/xxx"> 
    <soapenv:Header/> 
    <soapenv:Body> 
     <ser:GetCustomer> 
     <!--Optional:--> 
     <ser:GetCustomerRequest> <!-- this is a data contract --> 
      <ser:Id>?</ser:Id> 
     </ser:GetCustomerRequest> 
     </ser:GetCustomer> 
    </soapenv:Body> 
</soapenv:Envelope> 

no soy un desarrollador de Delphi, pero desarrolló un cliente simple prueba para ver lo que está pasando incorrecto. Esto es lo que Delphi envía como un sobre de SOAP.

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"> 
    <SOAP-ENV:Body SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:NS2="http://services.xxx.de/xxx"> 
    <NS1:GetCustomer xmlns:NS1="http://services.xxx.de/xxx"> 
     <GetCustomerRequest href="#1"/> 
    </NS1:GetCustomer> 
    <NS2:GetCustomerRequest id="1" xsi:type="NS2:GetCustomerRequest"> 
     <Id xsi:type="xsd:int">253</Id> 
    </NS2:GetCustomerRequest> 
    </SOAP-ENV:Body> 
</SOAP-ENV:Envelope> 

WCF genera un error que está en lengua alemana ...;)

Es wurde das endElement "cuerpo" aus espacio de nombres "http://schemas.xmlsoap.org/soap/envelope/" erwartet. Gefunden wurde "Element" NS2: GetCustomerRequest "aus Namespace" http://services.xxx.de/xxx "". Zeile 1, Posición 599.

significa algo así como

Se esperaba que el cuerpo. Pero en su lugar, se encontró el elemento "NS2: GetCustomerReques".

Ahora mi pregunta es: ¿Puedo de alguna manera cambiar la forma en que Delphi crea el sobre? ¿O las formas de hacer que WCF funcione con esos formatos de mensaje? ¡Cualquier ayuda es muy apreciada!

+1

El problema no es la pieza NS1 NS2. El problema es que Delphi está haciendo XML estructuralmente incorrecto. Parece que el servicio web espera que GetCustomerRequest se anide dentro de GetCustomer, pero el cliente Delphi no está anidando el elemento GetCustomerRequest. Aunque no sé cómo solucionarlo. ¿Generaste el cliente Delphi usando el WSDL del servicio WCF? –

Respuesta

16

Contrariamente a lo que algunas personas aquí parecen estar dando a entender, Delphi no está enviando inválida SOAP, es simplemente enviando RPC/codificado SOAP. Es muy fácil de reconocer de todos los atributos xsi:type. RPC/Encoded no es compatible con WS-I, pero es SOAP válido.

WCF, de forma predeterminada, utiliza el formato Documento/Literal/Envuelto SOAP, que Delphi 7 no puede manejar del lado del servidor y debe realizar algunos ajustes en el lado del cliente.

La solución más simple es decirle simplemente a Delphi que use el estilo de documento/literal. Lo haces activando soLiteralParams en el THttpRio.Converter.Options. Esto le dice a Delphi que no "desenrolle" los parámetros mientras está viendo. El aspecto "Documento" es algo que el importador Delphi WSDL normalmente puede resolver, por lo que no debería preocuparse por eso.

La otra solución es decirle al servicio de WCF para utilizar/estilo codificado RPC, que se puede hacer mediante la adición de los siguientes atributos para el servicio:

[ServiceContract] 
[XmlSerializerFormat(Style = OperationFormatStyle.Rpc, 
    Use = OperationFormatUse.Encoded)] 
public interface IMyService 
{ 
    // etc. 
} 

El segundo no es recomendable, ya que, como he mencionado antes, RPC/Encoded no es compatible con WS-I, sin embargo, la mayoría de los kits de herramientas SOAP sí lo reconocen, por lo que lo incluyo aquí como una posibilidad.

-1

Los marcos de Delphi y Java usan un espacio de nombres diferente. Una forma de hacer si es compatible es interceptar el xml prima y cambiar todos los "NS2" a lo que el deserializer espera

Saludos

+0

-1: para un analizador SOAP que cumpla con los estándares, el prefijo de espacio de nombre no importa en absoluto – mjn

3

que acabo de hacer uno de estos, y que terminó con una serie de llamadas StringReplace para alterar mi salida de XML para quitar los espacios de nombres en línea y hacer que se vea como el formato de SoapUI. Sí, hace falta mucho pirateo manual para hacerlo.

ejemplo:

Después de crear el RIO, llame a su propia proc BeforeExecute:

... 
EEUPSERTRIO.OnBeforeExecute := self.RIO_BeforeExecute; 
... 

procedure TMyWrapper.RIO_BeforeExecute(const MethodName: string; var SOAPRequest: WideString); 
{ 
Since Delphi isn't very good at SOAP, we need to fix the request so that the namespaces are correct. 
Basically, you take what Delphi gives you and try it in SoapUI. 
If yours doesn't work and SoapUI's version does, make yours look like theirs. 
} 

... Ahora Franja de formularios de los espacios de nombres en línea:

SOAPRequest := StringReplace(SOAPRequest,' xmlns:NS1="http://services.xxx.de/xxx"','',[rfReplaceAll,rfIgnoreCase]); 

. .. Muchos de estos.

A continuación, reemplazará el encabezado soap con uno que contenga los espacios de nombres que desee.

SOAPRequest := StringReplace(SOAPRequest,'xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"','xmlns:ns1="http://services.xyzcorp.com/xyz/EnterpriseEmployeeService_1_0" '+'xmlns:ns1="http://schemas.xyzcorp.com/TLOIntegration_HRO_Preview/TLOIntegration_1_0" ',[]); 

A continuación, puede volver a inyectar buenos:

ReplaceTag(SOAPRequest,'<metaData>','ns1:'); 
    ReplaceTag(SOAPRequest,'<trackingId>','ns1:'); 
    ReplaceTag(SOAPRequest,'<srcSystem>','ns1:'); 

Por último, puede capturar fácilmente su salida de Delphi por volver a consumir el WSDL con SoapUI y tener que organizar una mockservice.Luego, señale su aplicación como punto final y capturará la salida.
O puede usar Fiddler como proxy para capturar solicitudes.

+0

FYI - Estábamos usando D2005 con las correcciones de D2007. –

+2

Agregado a la lista de Delphi Nitpick ... http://stackoverflow.com/questions/2112729/biggest-delphi-nitpicks/2473684#2473684 –

+0

Gracias por tomar una decisión. Es el que realmente ayudó –

Cuestiones relacionadas