Cómo pasar "Null" (¡un apellido real!) a un servicio web SOAP en ActionScript 3
Tenemos un empleado cuyo apellido es Nulo. Nuestra aplicación de búsqueda de empleados se elimina cuando se utiliza ese apellido como término de búsqueda (lo que ocurre con bastante frecuencia ahora). El error recibido es:
<soapenv:Fault>
<faultcode>soapenv:Server.userException</faultcode>
<faultstring>coldfusion.xml.rpc.CFCInvocationException: [coldfusion.runtime.MissingArgumentException : The SEARCHSTRING parameter to the getFacultyNames function is required but was not passed in.]</faultstring>
El tipo de parámetro es string
.
Estoy usando:
- WSDL ( jabón )
- Flex 3.5
- ActionScript 3
- Fusión Fría 8
Tenga en cuenta que el error no ocurre al llamar al servicio web como un objeto desde una página de ColdFusion.
Rastreándolo
Al principio pensé que se trataba de un error de coerción en el que null
lo obligaban y pasaba "null"
una prueba . "null" == null
Que no es. Estuve cerca, pero muy, muy equivocado. ¡Lo lamento!
Desde entonces, he manipulado mucho en Wonderfl.net y rastreado el código en mx.rpc.xml.*
. En la línea 1795 de XMLEncoder
(en la fuente 3.5), en setValue
, todo XMLEncoding se reduce a
currentChild.appendChild(xmlSpecialCharsFilter(Object(value)));
que es esencialmente lo mismo que:
currentChild.appendChild("null");
Este código, según mi violín original, devuelve un elemento XML vacío. ¿Pero por qué?
Causa
Según el comentarista Justin Mclean en el informe de error FLEX-33664 , el siguiente es el culpable (consulte las dos últimas pruebas en mi violín que verifican esto):
var thisIsNotNull:XML = <root>null</root>;
if(thisIsNotNull == null){
// always branches here, as (thisIsNotNull == null) strangely returns true
// despite the fact that thisIsNotNull is a valid instance of type XML
}
Cuando currentChild.appendChild
se pasa la cadena "null"
, primero la convierte en un elemento XML raíz con texto null
y luego prueba ese elemento con el literal nulo. Esta es una prueba de igualdad débil, por lo que el XML que contiene null se convierte en el tipo null, o el tipo null se convierte en un elemento xml raíz que contiene la cadena "null", y la prueba pasa donde posiblemente debería fallar. Una solución podría ser utilizar siempre pruebas de igualdad estrictas al comprobar XML (o cualquier cosa, en realidad) en busca de "nulidad".
Solución
La única solución alternativa razonable que se me ocurre, aparte de corregir este error en todas las malditas versiones de ActionScript, es probar los campos en busca de "nulos" y escaparlos como valores CDATA .Los valores CDATA son la forma más adecuada de mutar un valor de texto completo que, de otro modo, causaría problemas de codificación/decodificación. La codificación hexadecimal, por ejemplo, está destinada a caracteres individuales. Se prefieren los valores CDATA cuando se escapa el texto completo de un elemento. La razón principal de esto es que mantiene la legibilidad humana.
En la nota xkcd , el sitio web Bobby Tables tiene buenos consejos para evitar la interpretación inadecuada de los datos del usuario (en este caso, la cadena "Null") en consultas SQL en varios idiomas, incluido ColdFusion .
De la pregunta no queda claro que esta sea la fuente del problema y, dada la solución señalada en un comentario a la primera respuesta (incrustar los parámetros en una estructura), parece probable que fuera otra cosa.
El problema podría estar en el codificador SOAP de Flex. Intente ampliar el codificador SOAP en su aplicación Flex y depure el programa para ver cómo se maneja el valor nulo.
Supongo que se pasa como NaN (no es un número). Esto arruinará el proceso de resolución de mensajes SOAP en algún momento (más notablemente en el servidor JBoss 5...). Recuerdo haber extendido el codificador SOAP y haber realizado una verificación explícita de cómo se maneja NaN.
@doc_180 tenía el concepto correcto, excepto que se centra en los números, mientras que el cartel original tenía problemas con las cadenas.
La solución es cambiar el mx.rpc.xml.XMLEncoder
archivo. Esta es la línea 121:
if (content != null)
result += content;
(Miré el SDK de Flex 4.5.1; los números de línea pueden diferir en otras versiones).
Básicamente, la validación falla porque 'el contenido es nulo' y por lo tanto su argumento no se agrega al paquete SOAP saliente; provocando así el error de parámetro faltante.
Tienes que extender esta clase para eliminar la validación. Luego hay una gran bola de nieve en la cadena, modificando SOAPEncoder para usar su XMLEncoder modificado, y luego modificando Operation para usar su SOAPEncoder modificado, y luego modificando WebService para usar su clase Operation alternativa.
Le dediqué algunas horas, pero necesito seguir adelante. Probablemente tomará uno o dos días.
Es posible que puedas simplemente arreglar la línea XMLEncoder y hacer algunos parches para usar tu propia clase.
También agregaré que si cambias a usar RemoteObject/AMF con ColdFusion, el valor nulo se pasa sin problemas.
Actualización del 16/11/2013 :
Tengo una adición más reciente a mi último comentario sobre RemoteObject/AMF. Si está utilizando ColdFusion 10; luego, las propiedades con un valor nulo en un objeto se eliminan del objeto del lado del servidor. Por lo tanto, debe verificar la existencia de las propiedades antes de acceder a ellas o obtendrá un error de tiempo de ejecución.
Comprueba así:
<cfif (structKeyExists(arguments.myObject,'propertyName')>
<!--- no property code --->
<cfelse>
<!--- handle property normally --->
</cfif>
Este es un cambio de comportamiento con respecto a ColdFusion 9; donde las propiedades nulas se convertirían en cadenas vacías.
Editar 6/12/2013
Dado que hubo una pregunta sobre cómo se tratan los valores nulos, aquí hay una aplicación de muestra rápida para demostrar cómo se relacionará una cadena "nulo" con la palabra reservada nulo.
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600" initialize="application1_initializeHandler(event)">
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
protected function application1_initializeHandler(event:FlexEvent):void
{
var s :String = "null";
if(s != null){
trace('null string is not equal to null reserved word using the != condition');
} else {
trace('null string is equal to null reserved word using the != condition');
}
if(s == null){
trace('null string is equal to null reserved word using the == condition');
} else {
trace('null string is not equal to null reserved word using the == condition');
}
if(s === null){
trace('null string is equal to null reserved word using the === condition');
} else {
trace('null string is not equal to null reserved word using the === condition');
}
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
</s:Application>
La salida del seguimiento es:
La cadena nula no es igual a la palabra reservada nula usando la condición! =
la cadena nula no es igual a la palabra reservada nula usando la condición ==
la cadena nula no es igual a la palabra reservada nula usando la condición ===
Al encadenar un null
valor en ActionScript se obtendrá la cadena "NULL"
. Mi sospecha es que alguien ha decidido que, por lo tanto, es una buena idea decodificar la cadena "NULL"
como null
, lo que provoca la rotura que ve aquí, probablemente porque estaban pasando null
objetos y obteniendo cadenas en la base de datos, cuando no querían eso (así que asegúrese de comprobar también ese tipo de error).
Como truco, podría considerar tener un manejo especial en el lado del cliente, convirtiendo una cadena 'nula' en algo que nunca ocurrirá, por ejemplo, XXNULLXX y convirtiéndola nuevamente en el servidor.
No es bonito, pero puede resolver el problema de un caso límite de este tipo.