views:

211

answers:

3

Hello all,

I have a Windows web server already set up with a website (unlimited application pools) and I want to be able to access a database on that server via the Android app I'm developing. How can I do this? Can someone point me to a tutorial or give code example of how this cross-platform (Android/Java to ASP.NET/C#) communication can be done?

(I'm trying to create a leader board or global scoreboard for my Android game on my server.)

Thanks.

+2  A: 

Sounds like a job for Web Services.

Start by creating a Web Service on the Windows web server, you can do this with ASP.NET (or maybe this might be more current).

On the Java side you can call the webservice and use the results that you get back. I think this question may help you get started on this side.

Vincent Ramdhanie
Thanks for responding. Your suggestion was helpful. Along with the help I got from SchlaWiener's response I was able to get it working. Thanks.
borg17of20
+3  A: 

Your app should expose a webservice. There is no native support for .net soap based webservices. But you can use the ksoap android port:

http://code.google.com/p/ksoap2-android/

which allows an android app to consume a .net asmx webservice. However the deserialisation of complex on the client side involves lot of code writing for every object you want so pass to the client.

I tried it for a project and there were some problems I ran into (either I could get result back to the client but the parameters i passed where always null or the other way - I could pass arguments but the result was null).

Here is an example I posted for getting an int: http://stackoverflow.com/questions/1052300/how-to-call-a-net-webservice-from-android-using-ksoap2/1521287#1521287

However, from my current knowlege I would suggest using a .asmx webservice that returns a json string and use a java json serialiser to parse the output. The advantages:

  • Write less code
  • Faster, since mobile devices don't always have good internet connections and the xml overhead from soap is bigger than json.

Quickstart:

  • Create a new asmx Webservice in your .net webapp.
  • Include a reference to System.Web.
  • Decorate your webservice class with [ScriptService] and your method with [ScriptMethod(ResponseFormat = ResponseFormat.Json)]

    [ScriptService]
    public class WebService1 : System.Web.Services.WebService 
    {
        [WebMethod]
        [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
        public string HelloAndroid()
        {
            return "Hello Android";
        }
    }
    

(I think you have to add a reference to System.Web.Extension.dll which is available since .net 3.5).

  • Your webservice will still return XML (so you can use it with a soap client) unless you make a HTTPPost request with content-type "application/json".

  • use this code to contact the webservice from android:

    private JSONObject sendJsonRequest(string host, int port,
           String uri, JSONObject param) 
                throws ClientProtocolException, IOException, JSONException
    {
        HttpClient httpClient = new DefaultHttpClient();
        HttpHost httpHost = new HttpHost(host, port);   
        HttpPost httpPost = new HttpPost(uri);
        httpPost.addHeader("Content-Type", "application/json; charset=utf-8");
    
    
    
    if (param != null)
    {
        HttpEntity bodyEntity = new StringEntity(param.toString(), "utf8");
        httpPost.setEntity(bodyEntity);
    }
    
    
    HttpResponse response = httpClient.execute(httpHost, httpPost);
    HttpEntity entity = response.getEntity();
    
    
    String result = null;
    if (entity != null) {
        InputStream instream = entity.getContent();
        BufferedReader reader = new BufferedReader(
             new InputStreamReader(instream));
        StringBuilder sb = new StringBuilder();
    
    
        String line = null;
        while ((line = reader.readLine()) != null)
            sb.append(line + "\n");
    
    
        result = sb.toString();
        instream.close();           
    }
    
    
    httpPost.abort();
    return result != null ? new JSONObject(result) : null;
    
    }

    if your webservice methods looks like this:

    [WebMethod]
    [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
    public User GetUser(string name, int age)
    {
        return new User { Name = name, Age = age; }
    }
    

    You can call it this way from android:

    public void getUser() {
        // if you put a json object to the server
        // the properties are automagically mapped to the methods' input parameters
        JSONObject param = new JSONObject();
        param.put("name", "John Doe");
        param.put("age", 47);
    
    
    
        JSONObject result = sendJsonRequest("server", 80, 
              "http://server:80/service1.asmx/GetUser", param);
        if (result != null) {
            JSONObject user = new JSONObject(result.getString("d"));
            // .net webservices always return the result
            // wrapped in a parameter named "d"
            system.out.println(user.getString("name"));
            system.out.println(user.getInt("age").toString());
        }
    
    }

Handling server exceptions on the client side:

  1. Add this class to your project:

    import org.json.JSONException;
    import org.json.JSONObject;
    
    
    public class JSONExceptionHelper {
    
    
    
    private static final String KEY_MESSAGE = "Message";
    private static final String KEY_EXCEPTIONTYPE = "ExceptionType";
    private static final String KEY_STACKTRACE = "StackTrace";
    
    
    public static boolean isException(JSONObject json) {
        return json == null 
            ? false
            : json.has(KEY_MESSAGE) && 
              json.has(KEY_EXCEPTIONTYPE) && 
              json.has(KEY_STACKTRACE);
    }
    
    
    public static void ThrowJsonException(JSONObject json) throws JSONException {
    
    
        String message = json.getString(KEY_MESSAGE);
        String exceptiontype = json.getString(KEY_EXCEPTIONTYPE);
        String stacktrace = json.getString(KEY_STACKTRACE);
    
    
        StringBuilder sb = new StringBuilder();
        sb.append(exceptiontype);
        sb.append(": ");
        sb.append(message);
        sb.append(System.getProperty("line.separator"));
        sb.append(stacktrace);
    
    
        throw new JSONException(sb.toString());
    }
    
    }

Now replace the return statement from the sendJSONRequest with:

    JSONObject json = result != null ? new JSONObject(result) : null
    if (JSONExceptionHelper.isException(json))
        JSONExceptionHelper.ThrowJsonException(json); 
    return json;

Please note: The exception is passed to the client only if connection comes from localhost. Otherwise you get an http error 500 (or 501? I can't remember). You have to configure your IIS to send error 500 to the client.

Try it out and create a webservice that always throws an exception.

SchlaWiener
That's the tricky part. If not all requirements are fullfiled by 100% ASMX has a fallback to XML. The requirements are: 1) .net 3.5 or with 2.0 there is an ajax pack available for download from MS. 2) Proper decoration with ScriptService and SciptMethod. 3) Request type has to be POST for security reason I believe 4) Content-Type has to be "application/json" 5) If you updated your project from VS2005 to 2008 the could be some values missing in the web.config file.
SchlaWiener
now your comment is missing? Maybe you solved the "xml instead of json" problem. Anyway, here are to good blog post about that problem:http://encosia.com/2010/03/03/asmx-and-json-common-mistakes-and-misconceptions/http://encosia.com/2010/05/31/asmx-scriptservice-mistake-invalid-json-primitive/
SchlaWiener
Yes, thanks. I did figure it out. I made a 1 character typo, which caused the server to return an xml string with: "Data at the root level is invalid. Line 1, position 1." It wasn't until I copied the entire error string into Word (it was truncated in Eclipse) that I found the error. I removed the comment, because it was a user error. I was hoping no one would notice. That said, your example and info in this post is simply the best I've received since joining this site. Aside from the error I made, my implementation went smoothly. Thank you very much.
borg17of20
I wrote a helper class that makes tracing exceptions that are thrown by .net easier. It basically checks if the output contains a stacktrace and rethrows it on the client side. I updated my answer with that.
SchlaWiener
A: 

In case you have trouble writing web methods which return array of objects, you may want to refer here:

http://seesharpgears.blogspot.com/2010/10/ksoap-android-web-service-tutorial-with.html

Hope it helps.

DFDF