soap etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
soap etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

23 Ekim 2011 Pazar

Android ile dataset dönen bir .NET webmethod'unu çağırmak. How to call a .NET webmethod which returns dataset using Android

Arkadaşlar merhaba,
(Hello guys)

10 yılı aşkın bir süredir profesyonel olarak yazılım sektörünün içinde olmam sebebiyle rahatlıkla söyleyebilirim ki gerçek hayat projelerinin neredeyse hiç birinde işler yazılımcının istediği şekilde ilerlemez.  Lafı uzatmadan android'de pek çok kişinin karşılaştığı ancak koca internette "1" tane bile örneğin bulunmadığı bu tür durumlardan birine değineceğim: Android ile .NET'te yazılmış dataset dönen bir webservise erişmek. Aslında hiçbirimiz dataset veya datatable gibi belli bir platforma (.NET) özel oluşturulmuş kompleks bir nesnenin webmethod gibi globallik arz eden bir yapıda dönüş değeri olarak kullanılmasını doğru bulmayacağız, bundan eminim. Fakat sizden böyle bir webmethod'la iletişime geçmenizin istendiğini ve bunun alternatifi olmadığını düşünün, ne yapacaksınız? Bu tamamen yanlış demeniz muhatabınız açısından ne kadar gerçekçi ve kabul edilebilir bir cevap olarak karşılanacak?

(As a professional developer who develops, plans and executes for 10 years, I can conveniently say without any doubt that in real life projects the things rarely comply with our plan. This example is one of them: Today we are going to mention about a case that there can not be found any tutorial on the internet about it, reaching a webservice which returns .NET dataset. I'm sure nobody wants to use these kind of complex objects like dataset or datatable -which runs only in .NET- as a parameter with a webmethod. However let's suppose that you are facing with a case that you need to call a webmethod like this and there is no any alternative way to do. Do they accept it as a reasonable answer when you say this is impossible? Or just think how they react when you say that.)

Gelin nasıl bu işin altından kalkacağımıza bakalım.
(Let's look how do we resolve that.)

Dediğimiz gibi bir webmethodumuz var ve dataset dönüyor. Önceki yazılarımızda 3. parti kütüphane kullanmadan (ksoap2 gibi) android ile bir webservise nasıl soap request atacağımızı ve geri dönüşü nasıl handle edeceğimizi anlatmıştık. Tüm bu bilgiler üzerine dataset dönen bir webmethod'un nasıl bir xml şemasına sahip olduğunu da bilirsek geriye kalan tek şey uygun yapıyı hazırlamak olacaktı ve öyle de oldu. Yeri gelmişken söylemekte fayda var bu tür envelope'un doğru oluşup oluşmadığını deneme amaçlı testlerde soapUI size büyük kolaylık sağlayacaktır.

(As I said there is a webmethod which returns dataset. I mentioned on previous tutorials that we need to know some key facts like how do we send soap request on android without using any third party library like ksoap2 and how do you handle return parameter which comes from AsyncClass on android -at the moment it supports turkish only-. In addition to this, if we know the xml schema of the soap response that comes from a webmethod which returns dataset then we can write the code very easily what we need.)

Bu noktadan sonra şu aşamada olduğumuzu varsayıyorum. (I suppose that we are here at this point)
  1. Soap envelope'umuz hazır,(we prepared the soap envelope)
  2. Webmethod'a başarıyla request attık. (we can call the webmethod without exception)
  3. Response'umuzu XML olarak aldık ve parse edilmeyi bekliyor. (we got the response as xml and it is waiting for parsing)
private DataTable parseAsDataTable(String x, String methodName){  
    //Datatable benim android için geliştirdiğim, .NET'teki DataTable nesnesinin içerdiği neredeyse bütün method ve özellikleri barındıran bir nesne. Siz bunun yerine 2 boyutlu bir object array kullanabilirsiniz. 
    //Datatable is an object that I created for android. It supports a lot of methods and properties of .NET datatable. But you can use 2 dimensional array instead of using this object -Object[row][column]-) 
    DataTable dt = new DataTable(Gonderim.this);
    try {
        String sMethodBaslangic = "<"+methodName+" xmlns=\"\">";
        String sMethodBitis = "";
        int artiBaslangic = sMethodBaslangic.indexOf(">");
        artiBaslangic++;
        int baslangic = x.indexOf(sMethodBaslangic);
        if(baslangic>-1){
            baslangic+=artiBaslangic;
            x = x.substring(baslangic);
            int bitis = x.indexOf(sMethodBitis);
            x = x.substring(0, bitis).replace(":", "_");
            x = new StringBuffer(x).insert(0,"<"+methodName+">").toString();
            x += "";        
            byte[] bytes = x.getBytes();
            ByteArrayInputStream bInputStream = new ByteArrayInputStream(bytes);


            // gelen string'i bir xml haline getiriyoruz.
            // converting string to xml
            DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
            org.w3c.dom.Document doc = docBuilder.parse (bInputStream);
            org.w3c.dom.Element element = doc.getDocumentElement();
            NodeList nl = element.getChildNodes();
            boolean takenColumnNames=false;
            String[] columnArray;
            String columnNames = "";
            int rowIndex =  nl.getLength();
            int colIndex = nl.item(0).getChildNodes().getLength();
            Object[][] dataSource = new Object[rowIndex][colIndex];


            for (int i = 0; i < rowIndex; i++) {
                NodeList nlChildren = nl.item(i).getChildNodes();
                for (int j = 0; j < nlChildren.getLength(); j++) {
                    Node node = nlChildren.item(j);
                    if(!takenColumnNames){
                        columnNames+=node.getNodeName()+",";
                    }
                    dataSource[i][j] = node.getChildNodes().item(0).getNodeValue();
                }
                takenColumnNames = true;
            }


           columnArray = columnNames.split(",");
           dt.setColumns(columnArray);
           dt.setDataSource(dataSource);
        }
    } catch (Exception e) {
        Util.setException(Gonderim.this, e);
    }
    return dt;
    }
Anlaşılmayan bir nokta olursa çekinmeden mesaj atabilirsiniz. İyi çalışmalar.
(Please feel free to contact me if you have any questions)


mgNet Library kullanımı
örnek video



6 Ekim 2011 Perşembe

3. party kütüphane kullanmadan (ksoap2) Android ile soap request işlemleri. Soap request on Android without using any third party library like ksoap2


Uzun bir aradan sonra tekrar merhaba.
(Hello again after a long time)

Büyük bir çoğunluk, android ile webservice'e bağlanmak istediğinde ksoap2'yi kullanıyor. Bunun zaman zaman dezavantajlarıyla karşılaşmış biri olarak size nasıl 3. party kütüphane kullanmadan kendi soap requestiniz ile bir webservice'e bağlanacağınızı açıklayacağım.
(A large majority of the android developers are using ksoap2 library when they want to connect to a webservice. As a man who encountered with disadvantages and advantages of these kind of libraries I will explain you how to send soap request without using any third party library -like soap2- on android)

HelloWorld adında bir webmethodumuz var, String türünde a değişkeni alıyor ve geriye a parametresinin değerine "türkçe karakterlerle doğru çalışıyor:" ibaresini ekleyerek dönüyor. Bilmeyenler .NET ile nasıl webservice yapılacağı konusunu anlatan ilgili örneğe buradan ulaşabilirler.
(There is a webmethod called HelloWorld. It takes a String as a parameter named a and returns with adding an expression which is "türkçe karakterlerle doğru çalışıyor" (which means it works correctly with turkish characters) to the return value. If you don't know how to create a webservice on .NET you can see the example by clicking here.)

[WebMethod]
public string HelloWorld(string a){
       return "türkçe karakterlerle doğru çalışıyor:  " + a;
}



Artık android tarafına geçebiliriz.
(Now we can go to the android side)

private void soapDeneme() {
  String envelope="<?xml version=\"1.0\" encoding=\"iso-8859-9\"?>"+
    "<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:encodingStyle=\"http://www.w3.org/2001/12/soap-encoding\">"+
    "<soap:Body>"+
    "<HelloWorld xmlns=\"http://tempuri.org/\">"+
    "<a>abcçdefgğhıijklmnoöprsştuüvyz</a>"+
    "</HelloWorld>"+
    "</soap:Body>"+
    "</soap:Envelope>";
  String url = "http://www.mustafaguven.com.tr/androidDenemeWebservice/Service1.asmx";
  String soapAction = "http://tempuri.org/HelloWorld";
  new CallWebService().execute(url,soapAction,envelope); 
 }

Yukarıda en çok dikkat edilmesi gereken şey request'imizi bir AsyncTask içerisinde call etmemiz. Aslında bu 3.0'ın altındaki herhangi bir versiyonda belki problem yaratmayabilir ancak honeycomb ile birlikte android bu tür işlemleri UI thread üzerinde yapmanıza izin vermeyecektir. (NetworkOnMainThreadExceptionDesigning For Responsiveness) Bunun için ya bir handler içerisinde call işlemini gerçekleştirmelisiniz ya da bizim bu örnekte yaptığımız gibi asynctask içerisinde.
(The most noticeable think above is that you must use another thread to call a webservice if the application which you are developing runs on the honeycomb (3.0) because UI thread does not support for this action otherwise it will be throwed out an exception called NetworkOnMainThreadException. for further information: Designing For Responsiveness)

 class CallWebService extends AsyncTask<String, String, String>{

  @Override
  protected String doInBackground(String... parameters) { 
   final DefaultHttpClient httpClient=new DefaultHttpClient(); 
   HttpParams params = httpClient.getParams(); 
   HttpConnectionParams.setConnectionTimeout(params, 10000); 
   HttpConnectionParams.setSoTimeout(params, 15000); 
   HttpProtocolParams.setUseExpectContinue(params, true); 
   HttpPost httppost = new HttpPost(parameters[0]);
   httppost.setHeader("soapaction", parameters[1]);
   httppost.setHeader("Content-Type", "text/xml; charset=iso-8859-9");

   String responseString="";
   try {
    HttpEntity entity = new StringEntity(parameters[2], "iso-8859-9");
    httppost.setEntity(entity);
    ResponseHandler rh=new ResponseHandlerTr();
    responseString=httpClient.execute(httppost, rh);
   }
   catch (Exception e) {
    Log.e("hata", e.getMessage());
   }
   httpClient.getConnectionManager().shutdown();
   return responseString;
  }
 }
(Yukarıda HttpEntity entity = new StringEntity(parameters[2], "iso-8859-9"); bölümünde charset'inizi "iso-8859-9" şeklinde belirtmezseniz webservice tarafında türkçe karakterlerin hepsi düzgün çalışmayacaktır.)
(You need to describe the encoding type as above to display turkish characters correctly)

Gelen response'da encoding yapmak için bu response'u handle etmemiz gerekli bunun için BasicResponseHandler class'ından extend ettiğimiz ResponseHandlerTr class'ını yazıyoruz.
(We are creating ResponseHandlerTr class which extends BasicResponseHandler to handle the response and encode it)

package com.quadro.main.Util;
import java.io.IOException;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpResponseException;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.util.EntityUtils;

public class ResponseHandlerTr extends BasicResponseHandler {
 @Override
 public String handleResponse(HttpResponse response) throws HttpResponseException, IOException      {
    StatusLine statusLine = response.getStatusLine();
         if (statusLine.getStatusCode() >= 300) {
             throw new HttpResponseException(statusLine.getStatusCode(),
                     statusLine.getReasonPhrase());
         }

         HttpEntity entity = response.getEntity();
         return entity == null ? null : EntityUtils.toString(entity, "iso-8859-9");
 }
 
}
Webservice'ten gelen cevap:
(The response comes from the webservice)



Anlaşılmayan bir nokta olursa çekinmeden danışabilirsiniz.
(Please feel free to contact me if you have any questions)