Android Tutorial Connect Android to MS SQL Server Tutorial

Status
Not open for further replies.
A new more powerful framework is now available: Remote Database Connector.

This tutorial is a follow up to the previous tutorial that explained how to connect to a MySQL database using a PHP web service. This time we will use an ASP.NET web service to connect to a Microsoft SQL Server.

Android cannot directly connect to the database server. Instead we will use HttpUtils to connect to a simple ASP.NET script that will issue the query and return the result as a JSON string.

There are several possible solutions for the web service implementation:
1. Pre-set the possible queries in the ASP script and then choose one of the queries by setting a parameter in the Http request.
2. Pass the query as-is to the database.

While the second solution is more flexible and doesn't require any changes to the ASP.NET script, it can also be more vulnerable to security attacks. For example a hacker can send a "DROP TABLE" query and erase all the data.
Making the database user a "read-only" user will protect this attack.

In this tutorial I will post the ASP.NET script that handles any query and passes it directly to the server. You can of course modify it and make it support only a set of queries.

ASP.NET code:
B4X:
<%@ Page Language="C#"%>
<%@ Import Namespace="System.Collections.Generic" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="System.Web.Script.Serialization" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
    protected void Page_Load(object sender, EventArgs ec)
    {
        using (SqlConnection cn = new SqlConnection("Database=Test1; User Id=UserName; password=Password")) //change as needed
        {
            using (StreamReader sr = new StreamReader(Request.InputStream, Encoding.UTF8))
            {
                Response.ContentType = "text/plain";
                string c;
                c = Request.QueryString["query"]; //for debugging with the browser
                //you can set the query by adding the query parameter  For ex: http://127.0.0.1/test.aspx?query=select * from table1
                if (c == null)
                    c = sr.ReadToEnd();
                try
                {
                    SqlCommand cmd = new SqlCommand(c, cn);
                    cn.Open();
                    SqlDataReader rdr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
                    List<Dictionary<string, object>> list = new List<Dictionary<string, object>>();
                    while (rdr.Read())
                    {
                        Dictionary<string, object> d = new Dictionary<string, object>(rdr.FieldCount);
                        for (int i =0;i < rdr.FieldCount;i++)
                        {
                            d[rdr.GetName(i)] = rdr.GetValue(i);
                        }
                        list.Add(d);
                    }
                    JavaScriptSerializer j = new JavaScriptSerializer();
                    Response.Write(j.Serialize(list.ToArray()));
              
                } catch (Exception e)
                {
                    Response.TrySkipIisCustomErrors = true;
                    Response.StatusCode = 500;
                    Response.Write("Error occurred. Query=" + c + "\n");
                    Response.Write(e.ToString());
              
                }
                Response.End();
            }
        }
    }
</script>
This code depends on System.Web.Extensions.dll.
To use this code you should save it as a file with aspx extension and modify the connection string with your values.
You may need to put System.Web.Extensions.dll in the bin folder (you will get a compilation error when the script runs if it is required and missing).
SS-2011-12-11_16.03.27.png


Before trying to connect from the Basic4android program, it is recommended to test that the script is working by calling it from the browser. It will be easier to read the error message this way. To help with debugging you can send the query as a GET parameter (later it will be sent as the payload).
B4X:
http://www.example.com/test1.aspx?query=select * from table_1

SS-2011-12-11_16.11.33.png


Now for Basic4android program:
B4X:
Sub Process_Globals
   Dim ServerUrl As String
   ServerUrl = "http://www.example.com/test1.aspx"
End Sub

Sub Globals

End Sub

Sub Activity_Create(FirstTime As Boolean)
   If FirstTime Then
      HttpUtils.CallbackActivity = "Main"
      HttpUtils.CallbackJobDoneSub = "JobDone"
   End If

   HttpUtils.PostString("Job1", ServerUrl, "SELECT col1, col2 FROM Table_1")
End Sub

Sub Activity_Resume
   If HttpUtils.Complete = True Then JobDone(HttpUtils.Job)
End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

Sub JobDone (Job As String)
   If HttpUtils.IsSuccess(ServerUrl) Then
      Dim parser As JSONParser
      Dim response As String
      response = HttpUtils.GetString(ServerUrl)
      parser.Initialize(response)
      Dim rows As List
      rows = parser.NextArray

      'work with result
      'rows is a List. Each item is a Map with the columns names as keys and the db values as the values.
      For i = 0 To rows.Size - 1
         Log("Rows #" & i)
         Dim m As Map
         m = rows.Get(i)
         Log("col1=" & m.Get("col1")) 'log the values of col1 and col2
         Log("col2=" & m.Get("col2"))
      Next
   End If
   HttpUtils.Complete = False
End Sub
This is the main activity code. Calling HttpUtils.PostString sends the request. When the request completes, Sub JobDone will be executed. After parsing the response with JSON parser we get a List. Each item in the list represents a row in the results set. Each item is a Map with the column names as keys and the db values as values.

When running the example, make sure to check the logs. Errors will be posted there.

The logs after a successful run:
B4X:
** Activity (main) Resume **
** Service (httputilsservice) Create **
** Service (httputilsservice) Start **
Rows #0
col1=23
col2=asdasd
Rows #1
col1=12323
col2=dwqd
Rows #2
col1=0
col2=1
Rows #3
col1=0
col2=1
** Service (httputilsservice) Destroy **
 

Attachments

  • MsSQL.zip
    6.3 KB · Views: 3,246
Last edited:

Kwame Twum

Active Member
Licensed User
Longtime User
Hi everyone, after querying a MSSQL database, I retrieve a JSON string which I format to suit my app.
However, when a record contains an image, say -
B4X:
j1.PostString(my_serva,"SELECT u_name, age, dp FROM gamers") 'dp is the field for images
- the JobDone is called after a very long time... (sometimes more than 1 min).

But if I query without asking for an image, say -
B4X:
j1.PostString(my_serva,"SELECT u_name, age FROM gamers")
- it's superfast.

The images in the database are very small too, all are 146px x96px and less than 30KB
What could be the issue? :(
 

Kwame Twum

Active Member
Licensed User
Longtime User
Erel, I'm rather retrieving it from the JSON string not adding the image to it..
 

Kwame Twum

Active Member
Licensed User
Longtime User
Erel, I think you're getting me wrong... I'm not sending data into the database... I'm rather retrieving data from it...
The resulting JSON is what I'm structuring...
I mean the data takes a longer time to be retrieved when it contains an image... Eventually, it does appear. But it takes too long.

The images are pushed into the database with a desktop app created with .NET
 
Last edited:

Kwame Twum

Active Member
Licensed User
Longtime User
Yes Erel, when the data finally get's to the app (after about a minute), the image is in the JSON string alright
 

Kwame Twum

Active Member
Licensed User
Longtime User
Thanks Erel, but that'll mean I have to place the images on the server directly instead of in the database right?

This is the actual code that stores the image on the server.. It's in VB.Net

B4X:
        Call connect() 'This opens a connection to the MSSQL server
        Dim cmdd As New SqlCommand
        cmdd.Connection = con
        cmdd.CommandText = "update gamers set dp = @img where u_name= '" & TextBox1.Text & "'"
        cmdd.Parameters.Add("@img", SqlDbType.Image).Value = File.ReadAllBytes(mii) 'mii contains the file path of the image selected
        con.Open()
        If cmdd.ExecuteNonQuery() = 1 Then
            MsgBox("Sent")
        End If
        con.Close()

I'm wondering what encoding that is...
 

Kwame Twum

Active Member
Licensed User
Longtime User
I believed that was handled automatically... I've always thought that when data is retrieved in the manner I'm requesting, it's always returned as a string, then parsed by the JSON library by calling:
B4X:
      JSONParser1.Initialize(Job.GetString)

Am I wrong?
 

Kwame Twum

Active Member
Licensed User
Longtime User
Erel, I tried it and it's a really long string indeed:
I changed the query to return only the image
B4X:
j1.PostString(my_serva,"SELECT dp FROM gamers WHERE age=1")
Result looked something like[{"dp":[255,216,225.............. (I've shortened it to save space on the thread)
and it was truncated.
 

Kwame Twum

Active Member
Licensed User
Longtime User
Thanks Erel, but all what you're saying refers to the process of retrieving the image after the JobString returns...

However, I just wanted to know why it took so long to return when it contained an image... and also if I could store the images in a manner that could speed reading from the database.

Once again, thanks.
 
Status
Not open for further replies.
Top