Intentando crear una solicitud SOAP correcta

He estado luchando durante horas tratando de construir la solicitud SOAP correcta usando ksoap2 para Android sin suerte. La solicitud ideal tiene este aspecto:

<?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Header> <AuthorizationToken xmlns="http://www.avectra.com/2005/"> <Token>string</Token> </AuthorizationToken> </soap:Header> <soap:Body> <ExecuteMethod xmlns="http://www.avectra.com/2005/"> <serviceName>string</serviceName> <methodName>string</methodName> <parameters> <Parameter> <Name>string</Name> <Value>string</Value> </Parameter> </parameters> </ExecuteMethod> </soap:Body> </soap:Envelope> 

Estoy utilizando el siguiente código para generar mi solicitud:

  SoapObject request = new SoapObject(NAMESPACE, METHOD); request.addProperty("serviceName", SERVICENAME); request.addProperty("methodName", METHODNAME); SoapObject nestedParameters = new SoapObject(NAMESPACE, "parameters"); SoapObject param = new SoapObject(NAMESPACE, "Parameter"); param.addProperty("Name", name); param.addProperty("Value", value); nestedParameters.addSoapObject(param); request.addSoapObject(nestedParameters); SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); envelope.setOutputSoapObject(request); envelope.dotNet = true; envelope.implicitTypes = true; envelope.headerOut = new Element[1]; Element header = new Element().createElement(NAMESPACE, "AuthorizationToken"); Element token = new Element().createElement(NAMESPACE, "Token"); token.addChild(Node.TEXT, this.AUTH_TOKEN); header.addChild(Node.ELEMENT, token); envelope.headerOut[0] = header; 

Lo que ksoap2 está construyendo es:

 <v:Envelope xmlns:i="http://www.w3.org/1999/XMLSchema-instance" xmlns:d="http://www.w3.org/1999/XMLSchema" xmlns:c="http://schemas.xmlsoap.org/soap/encoding/" xmlns:v="http://schemas.xmlsoap.org/soap/envelope/"> <v:Header> <n0:AuthorizationToken xmlns:n0="http://www.avectra.com/2005/"> <n0:Token>string</n0:Token> </n0:AuthorizationToken> </v:Header> <v:Body> <ExecuteMethod xmlns="http://www.avectra.com/2005/" id="o0" c:root="1"> <serviceName>AHAWebServices</serviceName> <methodName>MemberDirectory</methodName> <parameters i:type="n1:parameters" xmlns:n1="http://www.avectra.com/2005/"> <Parameter i:type="n1:Parameter"> <Name>string</Name> <Value>string</Value> </Parameter> </parameters> </ExecuteMethod> </v:Body> </v:Envelope> 

Tengo la sensación de que el problema está en el encabezado con los prefijos n0, pero no tengo ni idea de cómo deshacerse de ellos. Los quité del cuerpo fijando implicitTypes a la verdad pero no puedo encontrar una configuración similar para el jefe. Soy nuevo a SOAP así que cualquier otro consejo es apreciado grandemente. ¿Alguien tiene una idea de cómo podría arreglar esto?

Cuando se utiliza KSOAP Esto funcionó para mí

 SoapObject request = new SoapObject(WEBSERVICE_NAMESPACE, methodName); if(null != parameterMap && !parameterMap.isEmpty()){ for(Entry<String, String> entry: parameterMap.entrySet()){ request.addProperty(entry.getKey(), entry.getValue()); } } // Declare the version of the SOAP request SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); envelope.implicitTypes = true; envelope.dotNet = true; envelope.setOutputSoapObject(request); HttpTransportSE androidHttpTransport = new HttpTransportSE(ApplicationConstants.WEBSERVICE_WSDL_URL); // this is the actual part that will call the webservice try { androidHttpTransport.debug = true; androidHttpTransport.call(soapActionUrl, envelope); String ss = androidHttpTransport.responseDump; // Get the SoapResult from the envelope body. Log.d(TAG, "request: " + androidHttpTransport.requestDump); Log.d(TAG, "response: "+ androidHttpTransport.responseDump); SoapObject result = (SoapObject) envelope.getResponse(); Log.d("soap response", "" + result); } catch (IOException e) { Log.e(TAG, "IOException", e); } 

NOTA:

 androidHttpTransport.debug = true; 

Resuelto el problema en mi caso. Golpeé mi cabeza pero no podía razonar con la razón por la que depurar verdad ayudó a resolver el problema.

¿Por qué necesita usar ksoap? Simplemente tiene la parte estática de su solicitud SOAP como una cadena, agregue los valores a la parte estática y finalmente puede tener la solicitud SOAP completa. Por último, utilice métodos HTTP para enviar su solicitud de publicación.

No hay JAR adicionales

También ksoap tiene problemas como OOM para respuestas grandes, etc.

KSOAP OOM issue

Puede utilizar el código siguiente

 import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.HashMap; import java.util.Map.Entry; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.HttpConnectionParams; import org.apache.http.params.HttpParams; import org.apache.http.protocol.HTTP; import org.apache.http.util.EntityUtils; import android.util.Log; public final class SOAPRequest{ private static final String TAG = "SOAPRequest"; private static final String TAG_SOAP_HEADER_START = "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"><soap:Header>"; private static final String TAG_AUTHORIZATION_START = "<AuthorizationToken xmlns=\"http://www.avectra.com/2005/\">"; private static final String TAG_TOKEN_START = "<TOKEN>"; private static final String TAG_TOKEN_END = "</TOKEN>"; private static final String TAG_AUTORIZATION_END = "</AuthorizationToken>"; private static final String TAG_SOAPHEADER_END = "</soap:Header>"; private static final String TAG_SOAP_BODY_START = "<soap:Body>"; private static final String TAG_PARAM_NAME_START = "<Name>"; private static final String TAG_PARAM_NAME_END = "</Name>"; private static final String TAG_PARAM_VALUE_START = "<Value>"; private static final String TAG_PARAM_VALUE_END = "</Value>"; private static final String TAG_METHOD_START = "<methodName>"; private static final String TAG_METHOD_END = "</methodName>"; private static final String TAG_SERVICE_START = "<serviceName>"; private static final String TAG_SERVICE_END = "</serviceName>"; private static final String TAG_PARAMS_START = "<parameters><Parameter>"; private static final String TAG_EXE_METHOD_START = "<ExecuteMethod xmlns=\"http://www.avectra.com/2005/\">"; private static final String TAG_SOAP_REQ_END = "</Parameter></parameters></ExecuteMethod></soap:Body></soap:Envelope>"; /** * Constructor intentionally made private */ private SOAPRequest() { } /** * Builds a SOAP request with the specified value * @param token Value of token * @param serviceName Value of servicename * @param methodName Value of methodName * @param paramsMap Collection of parameters as set of name value pair which needs to be sent * @return the complete soap request */ public static String buildRequest(String token, String serviceName, String methodName, HashMap<String, String> paramsMap){ StringBuilder requestBuilder = new StringBuilder(TAG_SOAP_HEADER_START); requestBuilder.append(TAG_AUTHORIZATION_START); requestBuilder.append(TAG_TOKEN_START); requestBuilder.append(token); requestBuilder.append(TAG_TOKEN_END); requestBuilder.append(TAG_AUTORIZATION_END); requestBuilder.append(TAG_SOAPHEADER_END); requestBuilder.append(TAG_SOAP_BODY_START); requestBuilder.append(TAG_EXE_METHOD_START); requestBuilder.append(TAG_SERVICE_START); requestBuilder.append(serviceName); requestBuilder.append(TAG_SERVICE_END); requestBuilder.append(TAG_METHOD_START); requestBuilder.append(methodName); requestBuilder.append(TAG_METHOD_END); requestBuilder.append(TAG_PARAMS_START); for(Entry<String, String> param :paramsMap.entrySet()){ requestBuilder.append(TAG_PARAM_NAME_START); requestBuilder.append(param.getKey()); requestBuilder.append(TAG_PARAM_NAME_END); requestBuilder.append(TAG_PARAM_VALUE_START); requestBuilder.append(param.getValue()); requestBuilder.append(TAG_PARAM_VALUE_END); } requestBuilder.append(TAG_SOAP_REQ_END); return requestBuilder.toString(); } /** * Connection timeout set for the HttpClient */ private static final int CONNECTION_TIMEOUT= 6000; /** * Socket timeout set for the HttpClient */ private static final int SOCKET_TIMEOUT = 10000; /** * @return httpClient An instance of {@link DefaultHttpClient} */ private static DefaultHttpClient getHttpClient() { HttpParams httpParameters = new BasicHttpParams(); // Set the timeout in milliseconds until a connection is established. // The default value is zero, that means the timeout is not used. HttpConnectionParams.setConnectionTimeout(httpParameters,CONNECTION_TIMEOUT); // Set the default socket timeout (SO_TIMEOUT) // in milliseconds which is the timeout for waiting for data. HttpConnectionParams.setSoTimeout(httpParameters, SOCKET_TIMEOUT); return new DefaultHttpClient(httpParameters); } /** * Sends a SOAP request to the specified service endpoint. * * @param serviceEndpoint The service endpoint which will be hit * @param soapRequest The SOAP request * @return The string representing the response for the specified SOAP request. */ public static String send(String serviceEndpoint, String soapRequest){ HttpPost httppost = new HttpPost(serviceEndpoint); StringEntity se = null; try { se = new StringEntity(soapRequest,HTTP.UTF_8); } catch (UnsupportedEncodingException e) { Log.e(TAG,"send", e); return null; } se.setContentType("text/xml"); httppost.setHeader("Content-Type","application/soap+xml;charset=UTF-8"); httppost.setEntity(se); String result = null; HttpClient httpclient = getHttpClient(); try { HttpResponse httpResponse = httpclient.execute(httppost); HttpEntity responseEntity = httpResponse.getEntity(); if(null!= responseEntity){ //if you have a huge chunk of data read it using a buffer result =EntityUtils.toString(responseEntity); } } catch (ClientProtocolException e) { Log.e(TAG,"send", e); } catch (IOException e) { Log.e(TAG,"send", e); } catch (Exception e){ Log.e(TAG,"send", e); } return result; } } 

Creo que necesitas otra forma de crear el encabezado, parece jax-ws, así que iré con una implementación de jax ws que hice hace un par de meses.

Primero necesitas una clase HeaderHandler, que crea el elemento de cabecera del jabón, debería tener este aspecto:


  import javax.xml.namespace.QName; import javax.xml.soap.SOAPElement; import javax.xml.soap.SOAPEnvelope; import javax.xml.soap.SOAPHeader; import javax.xml.ws.handler.MessageContext; import javax.xml.ws.handler.soap.SOAPHandler; import javax.xml.ws.handler.soap.SOAPMessageContext; public class HeaderHandler implements SOAPHandler<SOAPMessageContext> { public boolean handleMessage(SOAPMessageContext smc) { Boolean outboundProperty = (Boolean) smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); String AUTH_TK = "http://www.avectra.com/2005/"; String PREFIX="";//no prefix String PREFIX_XMLNS="xmlns"; String value = "123456"; if (outboundProperty.booleanValue()) { try { SOAPEnvelope envelope = smc.getMessage().getSOAPPart().getEnvelope(); SOAPHeader header = envelope.addHeader(); //<AuthorizationToken xmlns="http://www.avectra.com/2005/"> SOAPElement authorizationToken = header.addChildElement("AuthorizationToken", PREFIX_XMLNS, AUTH_TK); //<Token>value</Token> SOAPElement usernameToken = authorizationToken.addChildElement("Token", PREFIX); usernameToken.addTextNode(value); } catch (Exception e) { e.printStackTrace(); } } return outboundProperty; } public Set<QName> getHeaders() { return null; } public void close(MessageContext arg0) { } public boolean handleFault(SOAPMessageContext arg0) { return false; } } 

Después de crear un HeaderHandlerResolver para manejar la creación de cabecera e insertarlo en una cadena de controlador:


  import java.util.ArrayList; import java.util.List; import javax.xml.ws.handler.Handler; import javax.xml.ws.handler.HandlerResolver; import javax.xml.ws.handler.PortInfo; public class HeaderHandlerResolver implements HandlerResolver { @SuppressWarnings("unchecked") public List<Handler> getHandlerChain(PortInfo portInfo) { List<Handler> handlerChain = new ArrayList<Handler>(); HeaderHandler hh = new HeaderHandler(); handlerChain.add(hh); return handlerChain; } } 

Después de eso, agrega en el Cliente:


  try{ //new service instance (your service should be extending javax.xml.ws.Service;) YourServiceProxy service = new YourServiceProxy(); //calls the header handler resolver ;) service.setHandlerResolver(new HeaderHandlerResolver()); //get the service YourService port = (YourService)service.getYourService(); //call the service port.yourMethod() } catch (Exception e) { e.printStackTrace(); } 

Por cierto, no he probado este encabezado en particular, he modificado un controlador de encabezado anterior que tenía, por lo que puede no ser exacto, pero creo que es muy cerca, realmente espero que te ayude, probarlo y decirnos cómo Se trata, voy a tratar de ayudarle si todavía no funciona.

¿Ha comprobado si los tipos generados por kSOAP para los parameters (es decir, i:type="n1:parameters" ) y los Parameter (es decir, i:type="n1:Parameter" ) son correctos (se definen en wsdl)?

Prueba a configurar

 envelope.implicitTypes = true; 

Y también jugar con

 envelope.setAddAdornments(false); 

Para obligar a kSOAP a no incluir el atributo de tipo y espacios de nombre.

conjunto

  envelope.implicitTypes = true; 

Y NO fijar

  envelope.setAddAdornments(false) 

Esto funcionó para mí.

  • Exhibición de la secuencia de la Cadena de Android Signo de porcentaje
  • ¿Cómo puedo cambiar el tamaño de un título CheckBox o hacer que envuelva en un xml PreferenceScreen?
  • Hacer texto en negrita y cursiva
  • ¿Hay alguna documentación de Android XML?
  • Java.lang.ClassCastException: android.view.ViewGroup $ LayoutParams no se puede convertir en android.widget.RelativeLayout $ LayoutParams
  • ¿Por qué el estilo y el diseño no usan el espacio de nombres de Android?
  • Imageview se borra
  • Android: java.lang.NoClassDefFoundError: com.google.android.gms.R $ styleable
  • Android - ¿Cómo manejar Webservice en XML?
  • Emoji símbolo 👍 en string.xml bloquea la aplicación
  • Eclipse: inhabilita la compilación de archivos XML mientras está en perspectiva de Java
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.