How to get Paramentro in a C# sent from Android web service

Asked

Viewed 1,189 times

1

I’m consuming a web service developed in C#, from an application on Android. By sending simple types per parameter such as string, int or long, I can usually get the information just by placing the same type in the Web service method declaration parameter. But I don’t know how to get a complex object created in java within the web service method in C#. The sent object has the same name in both applications, but are not exactly equal due to properties names.

Obs: -I’m using Ksoap2 on android, and the class is being serialized and sent to the web service without errors. -maybe I could get the object as XML, but what type I would put in the framework?

Web service call

SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);

        PropertyInfo object = new PropertyInfo();
        object.setName("obj");
        object.setValue(ordemServicoBO);
        object.setType(ordemServicoBO.getClass());

        request.addProperty(object);

        SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
        envelope.dotNet = true;
        envelope.encodingStyle = SoapSerializationEnvelope.ENC;
        envelope.setOutputSoapObject(request);
        envelope.addMapping(NAMESPACE, "ordemServicoBO",new OrdemServicoBO().getClass());
        envelope.implicitTypes = true;
        HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
        androidHttpTransport.debug = true;
        androidHttpTransport.setXmlVersionTag("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");

        androidHttpTransport.call(SOAP_ACTION, envelope);//Aqui a chamada é feita normalmente sem erro, e entra no método do web service

        SoapObject responseNoXML = (SoapObject)envelope.bodyIn;

Java class

public class OrdemServicoBO implements KvmSerializable {

private long idOrdemServico;
private long IdOrdemServicoCategoria;
private long idOrdemServicoLocal;
private long idHotel;
private long idUsuarioExecutante;
private long idUsuarioSolicitante;
private long idArea;
private String dataAbertura;
private String descricao;
private String status;
private AreaBO areaBO;
private UsuarioBO usuarioSolicitante;
private UsuarioBO usuarioExecutante;
private OrdemServicoCategoriaBO ordemServicoCategoriaBO;

public void setOrdemServicoCategoriaBO(OrdemServicoCategoriaBO ordemServicoCategoriaBO) {
    this.ordemServicoCategoriaBO = ordemServicoCategoriaBO;
}

public OrdemServicoCategoriaBO getOrdemServicoCategoriaBO() {
    return ordemServicoCategoriaBO;
}

public void setUsuarioExecutante(UsuarioBO usuarioExecutante) {
    this.usuarioExecutante = usuarioExecutante;
}

public void setUsuarioSolicitante(UsuarioBO usuarioSolicitante) {
    this.usuarioSolicitante = usuarioSolicitante;
}

public UsuarioBO getUsuarioExecutante() {
    return usuarioExecutante;
}

public UsuarioBO getUsuarioSolicitante() {
    return usuarioSolicitante;
}

public void setDataAbertura(String dataAbertura) {
    this.dataAbertura = dataAbertura;
}

public void setDescricao(String descricao) {
    this.descricao = descricao;
}

public void setIdArea(long idArea) {
    this.idArea = idArea;
}

public void setIdHotel(long idHotel) {
    this.idHotel = idHotel;
}

public void setIdOrdemServico(long idOrdemServico) {
    this.idOrdemServico = idOrdemServico;
}

public void setIdOrdemServicoCategoria(long idOrdemServicoCategoria) {
    IdOrdemServicoCategoria = idOrdemServicoCategoria;
}

public void setIdOrdemServicoLocal(long idOrdemServicoLocal) {
    this.idOrdemServicoLocal = idOrdemServicoLocal;
}

public void setIdUsuarioExecutante(long idUsuarioExecutante) {
    this.idUsuarioExecutante = idUsuarioExecutante;
}

public void setIdUsuarioSolicitante(long idUsuarioSolicitante) {
    this.idUsuarioSolicitante = idUsuarioSolicitante;
}

public void setStatus(String status) {
    this.status = status;
}

public String getDataAbertura() {
    return dataAbertura;
}

public long getIdArea() {
    return idArea;
}

public long getIdHotel() {
    return idHotel;
}

public long getIdOrdemServico() {
    return idOrdemServico;
}

public long getIdOrdemServicoCategoria() {
    return IdOrdemServicoCategoria;
}

public long getIdOrdemServicoLocal() {
    return idOrdemServicoLocal;
}

public long getIdUsuarioExecutante() {
    return idUsuarioExecutante;
}

public long getIdUsuarioSolicitante() {
    return idUsuarioSolicitante;
}

public String getDescricao() {
    return descricao;
}

public String getStatus() {
    return status;
}

public void setAreaBO(AreaBO areaBO) {
    this.areaBO = areaBO;
}

public AreaBO getAreaBO() {
    return areaBO;
}

@Override
public Object getProperty(int arg0)
{
    switch(arg0)
    {
        case 0:
            return getDataAbertura();
        case 1:
            return getDescricao();
        case 2:
            return getStatus();
        case 3:
            return getIdOrdemServicoCategoria();
        case 4:
            return getIdOrdemServico();
        case 5:
            return getIdOrdemServicoLocal();
        case 6:
            return getIdArea();
        case 7:
            return getIdHotel();
        case 8:
            return getIdUsuarioExecutante();
        case 9:
            return getIdUsuarioSolicitante();

    }
    return null;
}
@Override
public void setProperty(int arg0, Object arg1)
{
    switch(arg0)
    {
        case 0:
            setDataAbertura(arg1.toString());
            break;
        case 1:
            setDescricao(arg1.toString());
            break;
        case 2:
            setStatus(arg1.toString());
            break;
        case 3:
            setIdOrdemServicoCategoria(Long.parseLong(arg1.toString()));
            break;
        case 4:
            setIdOrdemServico(Long.parseLong(arg1.toString()));
            break;
        case 5:
            setIdOrdemServicoLocal(Long.parseLong(arg1.toString()));
            break;
        case 6:
            setIdArea(Long.parseLong(arg1.toString()));
            break;
        case 7:
            setIdHotel(Long.parseLong(arg1.toString()));
            break;
        case 8:
            setIdUsuarioExecutante(Long.parseLong(arg1.toString()));
            break;
        case 9:
            setIdUsuarioSolicitante(Long.parseLong(arg1.toString()));
            break;
    }

}
@Override
public void getPropertyInfo(int arg0, Hashtable arg1, PropertyInfo arg2)
{
    switch(arg0)
    {
        case 0:
            arg2.type = PropertyInfo.STRING_CLASS;
            arg2.name = "CategoryId";
            break;
        case 1:
            arg2.type = PropertyInfo.STRING_CLASS;
            arg2.name = "Description";
            break;
        case 2:
            arg2.type = PropertyInfo.STRING_CLASS;
            arg2.name = "Name";
            break;
        case 3:
            arg2.type = PropertyInfo.INTEGER_CLASS;
            arg2.name = "CategoryId";
            break;
        case 4:
            arg2.type = PropertyInfo.INTEGER_CLASS;
            arg2.name = "CategoryId";
            break;
        case 5:
            arg2.type = PropertyInfo.INTEGER_CLASS;
            arg2.name = "CategoryId";
            break;
        case 6:
            arg2.type = PropertyInfo.INTEGER_CLASS;
            arg2.name = "CategoryId";
            break;
        case 7:
            arg2.type = PropertyInfo.INTEGER_CLASS;
            arg2.name = "CategoryId";
            break;
        case 8:
            arg2.type = PropertyInfo.INTEGER_CLASS;
            arg2.name = "CategoryId";
            break;
        case 9:
            arg2.type = PropertyInfo.INTEGER_CLASS;
            arg2.name = "CategoryId";
            break;

        default:break;
    }

}
@Override
public int getPropertyCount()
{
    return 10;
}
}

Web service method C#

[WebMethod]
public OrdemServicoBO Exportar(OrdemServicoBO ordemServicoBO)//quando é executado o androidHttpTransport.call() é chamado esse método, mas o retorno, que é o mesno recebido por parâmetro, esta vazio.
{
    return ordemServicoBO; //Atualmente retorna vazio
}

class in C#

public class OrdemServicoBOAPP
{
    private long _idOrdemServico;

    public long IdOrdemServico
    {
        get { return _idOrdemServico; }
        set { _idOrdemServico = value; }
    }
    private long _IdOrdemServicoCategoria;

    public long IdOrdemServicoCategoria
    {
        get { return _IdOrdemServicoCategoria; }
        set { _IdOrdemServicoCategoria = value; }
    }
    private long _idOrdemServicoLocal;

    public long IdOrdemServicoLocal
    {
        get { return _idOrdemServicoLocal; }
        set { _idOrdemServicoLocal = value; }
    }
    private long _idHotel;

    public long IdHotel
    {
        get { return _idHotel; }
        set { _idHotel = value; }
    }
    private long _idUsuarioExecutante;

    public long IdUsuarioExecutante
    {
        get { return _idUsuarioExecutante; }
        set { _idUsuarioExecutante = value; }
    }
    private long _idUsuarioSolicitante;

    public long IdUsuarioSolicitante
    {
        get { return _idUsuarioSolicitante; }
        set { _idUsuarioSolicitante = value; }
    }
    private long _idArea;

    public long IdArea
    {
        get { return _idArea; }
        set { _idArea = value; }
    }
    private String _dataAbertura;

    public String DataAbertura
    {
        get { return _dataAbertura; }
        set { _dataAbertura = value; }
    }
    private string _descricao;

    public string Descricao
    {
        get { return _descricao; }
        set { _descricao = value; }
    }
    private string _status;

    public string Status
    {
        get { return _status; }
        set { _status = value; }
    }
    private AreaBOAPP _areaBO;

    public AreaBOAPP AreaBO
    {
        get { return _areaBO; }
        set { _areaBO = value; }
    }
}
  • Fernando, please post the relevant code. There are several libraries for Android capable of making unmarshalling XML on an object. My recommendation would be Simple.

  • I believe that if you send the object with the name of properties equal to c# itself will map this object.

  • I put the same name on the property and nothing’s changed. If I could get XML as a string I could mount the object manually, but I already switched to string and tbm comes empty.

  • If the webservice is yours and is in WCF I advise annotate the methods and create endpoints to work with Rest. Your life will be much easier. In any case, maybe Aerogear is for you: http://aerogear.org/

1 answer

2

From your code it seems that you have already learned to implement the interface KvmSerializable to map complex objects to XML and vice versa. Otherwise, see this example from Wsdl2code (which, by the way, is an excellent tool to generate this kind of Boilerplate code for you). Once you are with the mapping of complex objects ready, the call is fairly simple:

You’ve already added a mapping of a name to a class. In this case I don’t know if ordemServicoBO is a name of an element in the call or response of your service. In the case of the service Exportar you need to map the two to the same object type (OrdemServicoBO):

// Estou assumindo algumas coisas sobre o WSDL e o serviço Exportar
// O nome "ordemServicoBO" podem ser completamente diferente
// Em alguns casos pode ser que o request ou a resposta estejam encapsuladas, em
// outro objeto, etc
envelope.addMapping(NAMESPACE, "ordemServicoBO", new OrdemServicoBO().getClass());

Once this is done, let’s add the properties of request (as mapped above that provides for a parameter ordemServicoBO)

// Veja que novamente o nome desa propriedade depende do seu WSDL
request.addProperty("ordemServicoBO", ordemServicoBO);

When making the call, assuming the mappings are correct, your . NET side service will receive a full object:

 androidHttpTransport.call(SOAP_ACTION, envelope);

Again assuming that your WSDL returns a complex type of response directly in the body of the answer, to recover the value on the Android side just make a cast of that object:

 OrdemServicoBO result = (OrdemServicoBO) envelope.getResponse();

If there is any kind of indirect, you will need to handle it manually (see again example of Wsdl2code)

Getting the generated Xmls for the purpose of debugging:

androidHttpTransport.debug = true;
androidHttpTransport.call(SOAP_ACTION, envelope);

androidHttpTransport.requestDump; // string contendo a chamada
androidHttpTransport.responseDump // string contendo a resposta

TL;DR

  • You are already mapping complex types through the interface KvmSerializable
  • Now it’s a matter of matching the maps between namespaces, names and classes according to your WSDL.
  • Use the properties requestDump and responseDump to obtain Strings containing XML

Tips:

  • Use an external client such as Soapui to test calls and responses. Adjust the OrdemServicoBO until the variable requestDump is identical to the XML of request soapui.

  • Check your WSDL (example), all elements and mappings shall respond to namesin the tags <s:element>.

  • The tool Wsdl2code can generate all this for you.


Source: ksoap2-android - Coding Tips And Tricks

  • I’m gonna look at Wsdl2 and study him. I believe the serialization of is being done correctly, because it does not point out errors and the content of the bodyout seems to be correct. The obtaining of complex types as return of WS tbm is certain, because I’m already doing it without problems. But my doubt is in the part of sending complex objects in which you say "When making the call, assuming that the mappings are correct, your service on the side of the . NET will receive a full object", what is the type of parameter the . NET side will receive? a string with the XML of the sent object? Some XML type?

  • Hello Fernando. I think you are looking at it from the wrong perspective. The . NET can consume a DTO as you are doing without problems. With that the . NET will generate a WSDL for this and the other declared methods. Try appending ?wsdl at your service to see what . NET has generated. It is now your responsibility to make the customer serialize the object of request just like . NET expects to receive the object.

  • How are you trying to generate the request manually most likely making serialization errors (tip: pay attention to your method getPropertyInfo) and not using the item names expected by . NET.

  • So my tip is, or use the wsdl2code to generate everything cute from the WSDL (really do not have much to learn, just export the WSDL, submit on the site and download the client generated) or try to hit this kind of detail on the nail.

  • To hit this kind of detail on the nail again recommend you stick to the abstraction, use an external client with the Soapui to test the service manually and learn how to build the payloads for your service (since the problem is in the request). Once you’ve understood how yours web service works, make your code on Android build the exact same type of payload modifying the client code (you can get the XML raw through the method androidHttpTransport.requestDump). It became clearer?

  • What is important to be clear here is: At SOAP level what there are are payloads in the body of a Envelop. The whole job here is to get your client code to do marshalling of the object sent in the way that the service expects to receive in the request, and, similarly, unmarshalling correctly of what the service returns (this second part you said you have already hit).

  • 1

    Yes, I was looking at it from the wrong perspective. I sent the object as WS expected and with the help of requestDump made it much easier. Although C# automatically mount the object, something I don’t like very much. But anyway it worked and helped a lot. Thank you

  • I am happy to help Fernando. If the problem is solved do not forget to accept my answer ;).

Show 3 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.