Async Practice Networking and Database Access

In production, we need to talk to databases, local and remote storage (servers). From the point of the developers’ view, these operations can take a long time. We would like to ask for the operation to happen on the background thread and we can carry on doing other work on the calling thread. We need to be notified once the data is available from the background thread.

In my opinion, Calling Thread and Background Thread cannot be distinguished and it really depends on the point of the developers’ view. Let’s say, we need to download an HTML file from a remote server, by using Asynchronous programming technique, we initialise the download operation in the background thread and continue other operations on the Calling Thread, such as UI.

In some books, a concept called non-blocking call is introduced, which is similar to asynchronous. In other words, we don’t need to wait for the time-consuming operation completed on the calling thread. In production, almost all operations over the network and to any kind of storage, we should use asynchronous or nonblocking operations whenever available. The following drawing can give us a better understanding of the abstract concept…Sorry for my handwriting.

On the contrary, blocking calls means we need to wait for the operation to complete on the calling thread. Alternatively, we did not put the time-consuming operation on a background thread. The following drawing explains what is a blocking call.


Case Study – Downloading File

Let’s say we need to download a web page (an HTML file) from a location. The following code snippets demonstrate how it is done synchronously.

namespace Networking
 {
     [TestClass]
     public class Test_Download
     {
         string url = "http://deelay.me/5000/http://www.delsink.com";
         [TestMethod]
         public void Test_Download_DelsinkCOM()
         {
             var httpRequestInfo = HttpWebRequest.CreateHttp(url);
             //Initialise the round trip to server
             var httpResponseInfo = httpRequestInfo.GetResponse() as HttpWebResponse; 
             var responseStream = httpResponseInfo.GetResponseStream(); 
             //Download the page content from the server
             using(var sr = new StreamReader(responseStream))         
             {             
                  var webPage = sr.ReadToEnd();         
             }     
         } 
      }
 }

In line 12, the code initialises a round trip between the local PC and the remote server (or getting a response from a server). It can be time-consuming depends on the internet speed.

In this case, we send a web request and wait for a response, and the compiler stops in line 12 until we get a response. In other words, waiting for a response from the server actually block the rest implementation of the test method in the code snippet.

In production, the waiting may frustrate end-users, for example, Users’ UI may be blocked or frozen. Alternatively, we can put the file downloading task or operation on the background thread, instead of the calling thread. The solution is below.

[TestClass]
     public class Test_Download
     {
         string url = "http://deelay.me/5000/http://www.delsink.com";
         [TestMethod]
         public void Test_Download_DelsinkCOM()
         {
             var httpRequestInfo = HttpWebRequest.CreateHttp(url);
             var callback = new AsyncCallback(HttpResponseAvailable);
             var ar = httpRequestInfo.BeginGetResponse(callback, httpRequestInfo);             
             ar.AsyncWaitHandle.WaitOne(); 
         }
         private static void HttpResponseAvailable(IAsyncResult ar)     
         {         
             var httpRequestInfo = ar.AsyncState as HttpWebRequest;         
             var httpResponseInfo = httpRequestInfo.EndGetResponse(ar);         
             var responseStream = httpResponseInfo.GetResponseStream();
             using (var sr = new StreamReader(responseStream))         
             {             
                 var webPage = sr.ReadToEnd();         
             }     
          } 
     }

In line 10, we use a callback method, which is a delegate method. The BeginGetResponse method returns an IAsyncResult object.

Based on Microsoft’s documentation, IAsyncResult Interface represents the status of an asynchronous operation. I was quite confused at the beginning of this design. Eventually, I figured out, the code here is artificial and in production, there may be some other threads or code that needs to know the state of the implementation. In the above code snippet, we define a variable ar to keep the result of the BeginGetResponse method.

Another thing confuses me at the beginning, what is AsyncCallBack class doing here?

Based on Microsoft’s documentation, delegate void System.AsyncCallback(System.IAsyncResult ar) references a method to be called when a corresponding asynchronous operation completes.

In my opinion, in line 9, the variable callback is a method function pointer (or delegate) references to HttpResponseAvailable method in line 13. According to the above definition, callback method is called when a corresponding asynchronous operation completes; In this case, the asynchronous operation is the method in line 10.

In the Test_Download method, once the complier finishes line 10, Test_Download method will not wait for the completion of the callback method. As we move the callback method to a background thread, whereas we are now in a calling thread. However, the calling thread does not know the state of the background thread, and it just exits the method once it reaches the end.

To make sense, we manually pause the test method by the code in line 11 and the test method will continue once the background thread finishes what it was doing.

Before we finish this part of the asynchronous networking operation, I want to mention that how do we pass the url object to the callback method?

Have a look the code in line 10 ->

var ar = httpRequestInfo.BeginGetResponse(callback, httpRequestInfo);

We pass the HTTP request information via the second parameter in the above method. Based on Microsoft documentation, the second parameter is an object.

In the callback method, we need to cast the object to a HttpWebRequest type.

var httpRequestInfo = ar.AsyncState as HttpWebRequest; 

Case Study – Database Query With Begin/End

Compared with Networking, the communication between the local PC with the remote database can be time-consuming. It depends on the internet environment and etc.

In this case study, we will query a table from a remote database. The following code snippet is a synchronous demonstration.

[TestMethod]
         public void Test_DB_Sync()
         {
             string connectionString;
             connectionString = "password";
             string sqlSelect = "SELECT @@VERSION";         
             using(var sqlConnection = new SqlConnection(connectionString))
             {             
                 sqlConnection.Open();             
                 using(var sqlCommand = new SqlCommand(sqlSelect, sqlConnection))
                 {   
                     using(var reader = sqlCommand.ExecuteReader())
                     { while(reader.Read())
                       {   var data = reader[0].ToString();  }                 
                     }             
                 }         
             }     
        }

As we all know, talking with a server or database may cost time. The Test_DB_Sync method may get stuck in line 12, as the variable reader is waiting for a response from the database. The Test_DB_Sync method only continues when the response is available.

Alternatively, Let’s have a look at how does this work asynchronously. The expectation of this approach is, the Test_DB_Sync method does not get stuck in any line and we put the time-consuming task from the calling thread to the background thread.

[TestMethod]
public void Test_DB_Async()
{
   string connectionString;
   connectionString = "password";
   string sqlSelect = "SELECT @@VERSION";         
   using (var sqlConnection = new SqlConnection(connectionString))         
      {  
          sqlConnection.Open();             
          var sqlCommand = new SqlCommand(sqlSelect, sqlConnection);
          var callback = new AsyncCallback(DataAvailable);             
          var ar = sqlCommand.BeginExecuteReader(callback, sqlCommand);
          ar.AsyncWaitHandle.WaitOne();         
      }     
}     

private static void DataAvailable(IAsyncResult ar)     
{         
    var sqlCommand = ar.AsyncState as SqlCommand;         
    using(var reader = sqlCommand.EndExecuteReader(ar))         
    {             
         while(reader.Read())             
         {   
            var data = reader[0].ToString();             
         }         
    }     
}

The code above is similar to the networking execution. We execute the task by moving the communication task from the calling thread to the background thread.

In line 12, we initialise the background task by calling a callback method.


Async programming practice can be tricky in the beginning, and it may take time to sink in. Happy coding.

2 Replies to “Async Practice Networking and Database Access”

Leave a Reply

Your email address will not be published. Required fields are marked *