Come passare "Null" (un vero cognome!) A un servizio Web SOAP in ActionScript 3


4636

Abbiamo un dipendente il cui cognome è Null. La nostra applicazione di ricerca dei dipendenti viene interrotta quando quel cognome viene utilizzato come termine di ricerca (che sembra essere abbastanza spesso ora). L'errore ricevuto (grazie Fiddler!) È:

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

Carino, eh?

Il tipo di parametro è string.

Sto usando:

  • WSDL ( SOAP )
  • Flex 3.5
  • ActionScript 3
  • ColdFusion 8

Si noti che l'errore non si verifica quando si chiama webservice come oggetto da una pagina ColdFusion.


6
Potrebbe non essere di grande aiuto con il problema specifico, ma SOAP 1.2 consente valori nulli
JensG

6
Ho la sensazione che coinvolga Dave Null.
George Gibson,

2
Almeno non coinvolge Chuck Norris. Ecco perché stare lontano da lui nel codice: codesqueeze.com/…
SDsolar,

42
Il dipendente ha considerato di cambiare il suo nome?
Tatranskymedved il

11
Dovrebbe davvero prendere in considerazione l'acquisto di un cane Pointer e chiamarlo NullPointer.
Antonio Alvarez,

Risposte:


1109

Rintracciarlo

All'inizio ho pensato che si trattasse di un errore di coercizione in cui nullveniva costretto a superare "null"un test "null" == null. Non è. Ero vicino, ma molto, molto sbagliato. Mi dispiace per quello!

Da allora ho lavorato molto su wonderfl.net e ho rintracciato il codice mx.rpc.xml.*. Alla riga 1795 di XMLEncoder(nella fonte 3.5), in setValue, tutta la codifica XMLE si riduce a

currentChild.appendChild(xmlSpecialCharsFilter(Object(value)));

che è essenzialmente lo stesso di:

currentChild.appendChild("null");

Questo codice, secondo il mio violino originale, restituisce un elemento XML vuoto. Ma perché?

Causa

Secondo il commentatore Justin Mclean sulla segnalazione di bug FLEX-33664 , il colpevole è il seguente (vedi gli ultimi due test nel mio violino che lo verificano):

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
}

Quando currentChild.appendChildviene passata la stringa "null", la converte prima in un elemento XML radice con testo null, quindi verifica tale elemento rispetto al valore letterale null. Questo è un test di uguaglianza debole, quindi o l'XML contenente null viene forzato sul tipo null, oppure il tipo null viene forzato su un elemento xml radice contenente la stringa "null" e il test passa dove probabilmente dovrebbe fallire. Una soluzione potrebbe essere quella di utilizzare sempre rigorosi test di uguaglianza quando si controlla XML (o qualcosa del genere) per "nullità".

Soluzione

L'unica soluzione ragionevole che mi viene in mente, a parte correggere questo bug in ogni versione maledetta di ActionScript, è testare i campi "null" e sfuggirli come valori CDATA .

I valori CDATA sono il modo più appropriato per mutare un intero valore di testo che altrimenti causerebbe problemi di codifica / decodifica. La codifica esadecimale, ad esempio, è pensata per singoli personaggi. I valori CDATA sono preferiti quando stai sfuggendo all'intero testo di un elemento. La ragione principale di ciò è che mantiene la leggibilità umana.


298

Nella nota xkcd , il sito Web Bobby Tables offre buoni consigli per evitare l'interpretazione impropria dei dati dell'utente (in questo caso, la stringa "Null") nelle query SQL in varie lingue, incluso ColdFusion .

Non è chiaro dalla domanda che questa è la fonte del problema, e data la soluzione annotata in un commento alla prima risposta (incorporando i parametri in una struttura) sembra probabile che fosse qualcos'altro.


239

Il problema potrebbe essere nell'encoder SOAP di Flex. Prova ad estendere il codificatore SOAP nell'applicazione Flex e esegui il debug del programma per vedere come viene gestito il valore null.

La mia ipotesi è che è passato come NaN (Not a Number). Questo a volte farà confondere il processo di smascheramento del messaggio SOAP (in particolare nel server JBoss 5 ...). Ricordo di aver esteso il codificatore SOAP e di aver eseguito un controllo esplicito su come viene gestito NaN.


12
name = "Null" è ovviamente utile e non vedo come dovrebbe essere correlato a NaN.
Verifica il

129

@ doc_180 aveva il concetto giusto, tranne per il fatto che era focalizzato sui numeri, mentre il poster originale aveva problemi con le stringhe.

La soluzione è cambiare il mx.rpc.xml.XMLEncoderfile. Questa è la linea 121:

    if (content != null)
        result += content;

(Ho esaminato l'SDK di Flex 4.5.1; i numeri di riga potrebbero differire in altre versioni.)

Fondamentalmente, la validazione fallisce perché 'content is null' e quindi il tuo argomento non viene aggiunto al pacchetto SOAP in uscita; causando così l'errore del parametro mancante.

Devi estendere questa classe per rimuovere la validazione. Quindi c'è una grande palla di neve lungo la catena, modificando SOAPEncoder per usare il tuo XMLEncoder modificato, quindi modificando Operazione per usare il tuo SOAPEncoder modificato, e quindi moidfing WebService per usare la tua classe operativa alternativa.

Ci ho passato alcune ore, ma devo andare avanti. Probabilmente ci vorranno un giorno o due.

Potresti essere in grado di correggere la linea XMLEncoder ed eseguire alcune patch scimmia per utilizzare la tua classe.

Aggiungerò anche che se si passa all'uso di RemoteObject / AMF con ColdFusion, il null viene passato senza problemi.


16/11/2013 aggiornamento :

Ho un'aggiunta più recente al mio ultimo commento su RemoteObject / AMF. Se si utilizza ColdFusion 10; quindi le proprietà con un valore null su un oggetto vengono rimosse dall'oggetto lato server. Quindi, devi controllare l'esistenza delle proprietà prima di accedervi o otterrai un errore di runtime.

Controlla in questo modo:

<cfif (structKeyExists(arguments.myObject,'propertyName')>
 <!--- no property code --->
<cfelse>
 <!--- handle property  normally --->
</cfif>

Questo è un cambiamento nel comportamento rispetto a ColdFusion 9; dove le proprietà null si trasformerebbero in stringhe vuote.


Modifica il 06/12/2013

Dato che c'era una domanda su come vengono trattati i null, ecco una rapida applicazione di esempio per dimostrare come una stringa "null" si collegherà alla parola riservata null.

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

L'output della traccia è:

la stringa null non è uguale alla parola riservata null usando la condizione! =

la stringa null non è uguale alla parola riservata null utilizzando la condizione ==

la stringa null non è uguale alla parola riservata null utilizzando la condizione ===


8
@ Reboog711 Il cognome dell'impiegato è letteralmente la stringa "Null" come in "My name is Pat Null" La tua risposta non riesce a passare il cognome dell'impiegato. La tua risposta nasconde semplicemente il fatto che "Null" è stato impropriamente costretto al concetto di linguaggio null dal metodo appendChild () come descritto da Ben Burns. Il risultato è ancora il fallimento del sistema nel trattare con Mr. o Ms. Null.
Maxx Daymon,

2
@MaxxDaymon Penso che tu abbia frainteso quale sia la mia risposta in realtà. Non presenta una soluzione; ma piuttosto una spiegazione del perché si verifica il problema; e cita il codice pertinente dal Flex Framework. La mia modifica più recente è forse fuori luogo; poiché discute di un approccio alternativo e non è direttamente correlato alla domanda originale.
JeffryHouser,

1
Sei sulla strada giusta, ma a quel punto nel codice contentc'è la stringa "null"e "null" == null restituisce false, quindi il test si comporta come previsto. Invece credo che il problema sia un mix di come XML.appendChild gestisce un argomento stringa e come un elemento XML radice contenente solo la stringa "null" può essere costretto a un valore letterale null.
Ben Burns,

@ Reboog711 Dai un'occhiata al mio violino. "null"! = null` truequi è il comportamento desiderato. Se accadesse il contrario, ciò eliminerebbe la stringa "null" dal processo di codifica, che in realtà sarebbe la causa del problema. Tuttavia, poiché questo test ha esito positivo, l'encoder continua fino a quando XML.appendChild lo scarta a causa di un bug di coercizione.
Ben Burns,

4
Nessun problema. Se vuoi vedere il vero problema, aggiungi var xml:XML = <root>null</root>; var s:String = (xml == null) ? "wtf? xml coerced to null?!!" : "xml not coerced to null."; trace(s);al tuo esempio di codice.
Ben Burns,

65

Traduci tutti i caratteri nei loro equivalenti esadecimali. In questo caso, Nullverrebbe convertito in&#4E;&#75;&#6C;&#6C;


41
Per favore, non farlo. CDATA è stato creato per l'uso nei casi in cui è necessario sfuggire a un intero blocco di testo.
Ben Burns,

4
Potrei sbagliarmi, ma non penso che il downvoting solo perché non era la tua soluzione è come dovrebbe funzionare. Inoltre, è necessario tenere presente che il problema richiede una soluzione euristica poiché non esiste un modo ovvio, come evidenziato dalla varietà di soluzioni pubblicate. Infine, tenendo a mente che non conosco CF, un decodificatore non equivarrebbe solo a equiparare il testo interno di <message><![CDATA[NULL×[> </message> al testo interno di <message> NULL </ messaggio>? Se è così, allora CDATA è davvero una soluzione?
doogle,

7
Ho annullato il downgrade perché si tratta di un modello anti-pattern. Il bug in questo caso non è in CF, è in ActionScript. Tuttavia, sollevi comunque un buon punto. Aggiungerò un test al mio violino per la codifica CDATA.
Ben Burns,

51

La stringa di un nullvalore in ActionScript darà la stringa "NULL". Il mio sospetto è che qualcuno ha deciso che è, quindi, una buona idea per decodificare la stringa "NULL"come null, causando la rottura che vedete qui - probabilmente perché dato che anche in nulloggetti e ottenere le stringhe nel database, quando non volevano quello (quindi assicurati di controllare anche quel tipo di bug).


Sì, ci sono un certo numero di possibilità qui che richiederanno più debug per restringere. 1) Il WSDL è usato qui abbastanza espressivo per distinguere tra "NULL" come valore stringa e valore effettivo nullo (o omesso)? 2) In tal caso, il client sta codificando correttamente il cognome (come stringa e non un valore letterale nullo) 3) In tal caso, il servizio sta interpretando correttamente "NULL" come stringa o lo sta costringendo a un valore null?
pimlottc,

39

Come hack, potresti considerare di avere una gestione speciale sul lato client, convertendo la stringa 'Null' in qualcosa che non si verificherà mai, ad esempio XXNULLXX e riconvertendo il server.

Non è carino, ma può risolvere il problema per un caso del genere.


32
XXNULLXX potrebbe anche essere un nome. Non lo sai. Forse le persone in Indonesia non hanno il cognome e usano una variante di XXX come cognome quando richiesto.
gb.

3
Stesso concetto, ma aggiorna tutti i nomi nel database e la prefazione quindi con qualche carattere (1Null, 1Smith). Elimina quel personaggio nel client. Naturalmente questo potrebbe essere un lavoro acaro rispetto alla soluzione di Reboog.
bobpaul

14
@BenBurns Sì, ma cosa succede se voglio nominare mio figlio &#78;&#117;&#108;&#108;?
Sirene,

@Sirens Non è questo il problema. Se il mio nome è "<& quot;>", allora mi aspetto che sia correttamente evitato come & quot; & lt; & amp; quot; & gt; & quot ;, questo è ovvio. Il vero problema è che un'applicazione si comporta come se utilizzasse una lista nera per i nomi.
Mr Lister,

30

Bene, immagino che l'implementazione di Flex dell'encoder SOAP sembra serializzare i valori null in modo errato. Serializzarli come String Null non sembra essere una buona soluzione. La versione formalmente corretta sembra passare un valore null come:

<childtag2 xsi:nil="true" />

Quindi il valore di "Null" non sarebbe altro che una stringa valida, che è esattamente quello che stai cercando.

Immagino che risolvere questo problema in Apache Flex non dovrebbe essere così difficile. Consiglierei di aprire un problema con Jira o di contattare i ragazzi della mailing list di apache-flex. Tuttavia, ciò risolverebbe solo il lato client. Non posso dire se ColdFusion sarà in grado di lavorare con valori null codificati in questo modo.

Vedi anche il post sul blog di Radu Cotescu Come inviare valori Null nelle richieste soapUI .


6
Ci sono buone informazioni qui, quindi non voglio sottovalutare, ma ho pensato che valesse la pena commentare. Per impostazione predefinita, XMLEncoder.as codificherà nullcorrettamente un valore vero , impostando xsi:nil="true"sull'elemento. Il problema sembra in realtà essere nel modo in cui il XMLtipo stesso di ActionScript (non il codificatore) gestisce la stringa "null".
Ben Burns,

22

È un kludge, ma supponendo che ci sia una lunghezza minima per SEARCHSTRING, ad esempio 2 caratteri, substringil SEARCHSTRINGparametro al secondo carattere e passarlo invece come due parametri: SEARCHSTRING1 ("Nu")eSEARCHSTRING2 ("ll"). Concatenate li ricongiungono insieme quando si esegue la query nel database.


32
CDATA è stato aggiunto alle specifiche XML per evitare questi tipi di kludges.
Ben Burns,

8
Non è necessario sfuggire a "Null" con CDATA, non esiste una parola chiave null in XML.
Devo dire che il

6
Concordo con @eckes. Non capisco perché si parla di CDATA. CDATA è utile solo per sfuggire a caratteri che hanno un significato speciale in XML. nessuno di: n, u, lhanno la semantica speciali in XML. "NULL" e "<! [CDATA [NULL]]>" sono identici a un parser XML.
jasonkarns,

9
@jasonkarns - Sono d'accordo al 100% sul fatto che non ci dovrebbe essere nulla di speciale sul nodo stringa / testo NULL, ma essere pedante <blah>null</blah>e <blah><![CDATA[null]]>non essere lo stesso per un parser XML. Essi dovrebbero producono gli stessi risultati, ma il flusso logico per loro movimentazione è diverso. È questo effetto che stiamo sfruttando come soluzione alternativa al bug nell'implementazione XML flessibile. Sostengo questo su altri approcci in quanto preserva la leggibilità del testo e non ha effetti collaterali per altri parser.
Ben Burns,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.