• Uncategorized

Asynchronous Data Access using Callback Model

Ability to execute several tasks on different threads at the same time.Through Asynchronous call the main thread never blocked and another thread calls the method and gives the output to the main thread.

The problem with the ADO.Net 1.x is that one thread has to wait for the other thread to complete. So to overcome this problem Microsoft has introduced Asynchronous data access, through which one can execute multiple threads at a time.Asynchronous access to the results of multiple commands over the same Connection instance, plus the ability to open connections asynchronously. A database operation is normally a synchronous operation, meaning that the caller regains the control of the application only when the interaction with the database has completed.This way of working may pose performance and scalability issues incases of lengthy operations. ADO.NET 2.0 provides true asynchronous support for two specific scenarios: opening connections and executing commands. Leveraging these features, you can open a connection and populate the command object while the connection is physically established. This is a clear performance advantage, because it really gives you a bit of parallelism if SQL Server lives on a remote machine.

Although asynchronous execution can be a nice feature, it should not be used gratuitously; only use it if you know the command can run for a long time and also that you have something useful to do at the same time. The Windows thread scheduler in the Windows NT family of operating systems (the feature is not available on Windows 9x and ME clients) takes overhead of its own to switch between threads. Also bear in mind that some .NET libraries are thread-sensitive; using asynchrony, the thread that you use to start the operation wo’t necessarily be the same thread it finishes on. Not only can asynchronous operation be effective for multiple action statements and stored procedure execution, when used with the Multiple Active Result Sets (MARS) feature in SQL Server 2005, you can multiplex asynchronous SELECT statements using a single database connection.

Asynchronous code is difficult to write and debug, more advanced coding skills are required.

Executing Multiple Commands Sequentially An alternative situation is when you use several object instances to access data (here multiple DataReader instances, but it could be a mix of DataReader and DataSet instances) over the same connection. Again,only one of these can be executing a query over the single connection at a time. But because the ADO.NET code you write will usually call methods on the DataReader or other objects sequentially and will block on each method call until it is complete, there is no problem with using the same connection. Figure below shows this scenario.

pic1

this case, however, there are two areas where performance and usability issues can arise:
1. If you open a rowset with a DataReader over the connection, you must close it before you attempt to open another DataReader or execute another command�if not, you�ll get a �Connection is busy . . .� error.To be able to open more than one rowset concurrently in ADO.NET version1.x requires that each command have its own separate connection to the database. Because the number of database connections available islimited and they are expensive in terms of resource usage, this often is not a feasible approach.
2. If one of the commands you�re executing takes a long time to return results, the code in the application will block and wait until the query process is complete before it can execute the next command.
So your code may be standing idle when it could be doing something else in the meantime.

New API Elements
We modeled the new ADO.NET asynchronous API after the existing APIs in the .NET Framework, with similar functionality. Consistency is an important thing in large frameworks
Asynchronous Methods
All command execution APIs are in the Command object in ADO.NET,including ExecuteReader, ExecuteNonQuery, ExecuteXmlReader andExecuteScalar. We decided to minimize the API surface that we added forthis feature, so we added asynchronous versions only for the methodsthat could’t be adapted from other methods: ExecuteReader,ExecuteNonQuery and ExecuteXmlReader. ExecuteScalar is simply a short form of ExecuteReader + fetch first row/first column + close the reader, so we did’t include an asynchronous version of it.
Following the asynchronous API pattern already in use in the .NET Framework, each existing synchronous method has now an asynchronous counterpart that’s split into two methods; a begin part that starts the work, and an end part that completes it. The table below summarizes the new methods in the command object:
Table 1. New asynchronous methods available in ADO.NET 2.0

pic2

 

The asynchronous pattern models methods, so the begin method takes all the input parameters, and the end method provides all the output parameters, as well as the return value. For example, here is what an asynchronous invocation of ExecuteReader lookslike.
The “async” Connection String Keyword
In order to use asynchronous commands, the connections on which the commands will be executed must be initialized with async=true in the connection string. An exception will be thrown if any of the asynchronous methods are called on a command with a connection that does’t have async=true in its connection string.

BeginExecuteReader
Starts an asynchronous query to the data source that is expected to return some rows. The return value is a reference to an object that implements the IAsyncResult interface, in this case an instance of the SqlAsyncResult class, which is used to monitor and access the process as it runs and when it is complete.
Ex : async-result = command.BeginExecuteReader(callback, state)
It takes an AsyncCallback instance that specifies the callback routine to be executed when the process is complete, plus an Object that defines state information for the process.

EndExecuteReader
Once the command execution started by a BeginExecute Reader call hascompleted, this method is called to access the results. The single parameter is a reference to the SqlAsyncResult for the command, and themethod returns a DataReader that references the rowset(s) returned by the query (in the same way the ExecuteReader method does for synchronous processes).
Ex: data-reader = command.EndExecuteReader(async-result).

Models in Asynchronous

1. The Asynchronous Polling Model
The simplest approach to handling asynchronous execution of one or more commands is through the polling model. It simply involves starting off the and then repeatedly checking the IsCompleted property of the SqlAsyncResult instance until it returns True.Of course, the code can go off and do other things between checking to see whether the process is complete. However, this approach is notrecommended unless it is a simple and “tight” loop that handles aspecific required task and uses only minimal processing time. If there are large or unrelated tasks to accomplish, you should consider using the callback or wait models instead.

2. The Asynchronous Callback Model
Thesecond approach to asynchronous execution involves providing a routine in the code that will act as a callback. It will be executed when the action you specify occurs, rather like the way that an event handler is called to handle a user�s
interaction with an application.To specify the callback routine you create a new instance of the AsyncCallback class, providing the name of that routine as the parameter,and pass this AsyncCallback instance into the method you use to start execution of the command. Asynchronous technique employs the familiar asynchronous programming model using the AsyncCallback delegate in.NET, and so includes the SqlAsyncResult class to implement the IAsyncResult interface. While this feature works only for SqlClient at the moment.IAsyncResult Interface : Represents the status of an asynchronousoperation.The IAsyncResult interface is implemented by classes containing methods that can operate asynchronously. An object that supports the IAsyncResult interface stores state information for an asynchronous operation, and provides a synchronization object to allow threads to besignaled when the operation completes.

3. The Asynchronous Wait Model
The mostcomplex of the asynchronous methods is also the most efficient if all you want to do is start some commands running against one or more datasources (they can all use separate connections and therefore different databases if required) and not execute other code in the meantime. You simply want to wait until one, more, or all of the commands have completed and then perhaps display some results. In this case, you start each process in the same way as the previous examples but then use the AsyncResult to create a WaitHandle that you use to monitor each process.

The following code explains the usage of techniques of asynchronous programming and multithreading.

Asynchronous Callback Model Example:

 

   1:  using System;
   2:  using System.Data;
   3:  using System.Data.SqlClient;
   4:   
   5:  // You'll need this delegate in order to fill the grid from a thread other than the form's thread. See the Callback1 
   6:  //procedure for more information.
   7:  private delegate void DelFillGrid(SqlDataReader reader);
   8:   
   9:  // You'll need this delegate to update the status bar.
  10:  private delegate void DisplayStatusDelegate(string Text);
  11:   
  12:  // It indicates whether asynchronous command is active or closed.
  13:  private bool isExecuting = false;
  14:   
  15:  private SqlConnection conn = null;
  16:   
  17:  private void DisplayStatus(string Text)
  18:  {
  19:  this.label1.Text = Text;
  20:  }
  21:   
  22:  private void FillGrid(SqlDataReader dr)
  23:  {
  24:  try
  25:  {
  26:  DataTable dt = new DataTable();
  27:  dt.Load(dr);
  28:  this.dataGridView1.DataSource = dt;
  29:  DisplayStatus("Ready");
  30:  }
  31:  catch (Exception ex)
  32:  {
  33:  // Because you're guaranteed this procedure
  34:  // is running from within the form's thread,
  35:  // it can directly interact with members of the form.
  36:  DisplayStatus(string.Format("Ready (last attempt failed: {0})", ex.Message));
  37:  }
  38:  finally
  39:  {
  40:  // Do't forget to close the connection, as well.
  41:  if (dr != null)
  42:  {
  43:  dr.Close();
  44:  }
  45:  if (conn!= null)
  46:  {
  47:  conn.Close();
  48:  }
  49:  }
  50:  }
  51:   
  52:  private void btnAsync_Click(object sender, System.EventArgs e)
  53:  {
  54:  if (isExecuting)
  55:  {
  56:  MessageBox.Show(this, "Already executing. Please wait until the current query " + "has completed.");
  57:  }
  58:  else
  59:  {
  60:  SqlCommand command = null;
  61:  try
  62:  {
  63:  DisplayStatus("Connecting…");
  64:  //To Execute the command asynchronously we need to make Asynchronous Processing=true
  65:  conn= new SqlConnection("Data Source=localhost;Integrated Security=SSPI;Initial Catalog=Northwind; );
  66:  Asynchronous Processing=true"
  67:  // To emulate a long-running query, wait for a few seconds before retrieving the real data.
  68:  command = new SqlCommand();
  69:  command.CommandText = "WAITFOR DELAY '00:00:05' : SELECT * FROM Customers" ;
  70:  command.Connection = conn; 
  71:  conn.Open();
  72:   
  73:  DisplayStatus("Executing…");
  74:  isExecuting = true;
  75:   
  76:  //Passing the SQLCommand as a parameter makes easier to call EndExecuteReader(); 
  77:  AsyncCallback callback = new AsyncCallback(Callback1);
  78:  command.BeginExecuteReader(callback, command);
  79:  }
  80:  catch (Exception ex)
  81:  {
  82:  DisplayStatus("Error: " + ex.Message);
  83:  if (conn!= null)
  84:  {
  85:  conn.Close();
  86:  }
  87:  }
  88:  }
  89:  }
  90:   
  91:  private void Callback1(IAsyncResult result)
  92:  {
  93:  try
  94:  {
  95:  // To retrieve the original command object.
  96:  SqlCommand command = (SqlCommand)result.AsyncState;
  97:  SqlDataReader dr = command.EndExecuteReader(result);
  98:  // To execute the code from a different thread instead of main thread.
  99:  DelFillGrid del = new DelFillGrid(FillGrid);
 100:  // To call the form's delegate.
 101:  this.Invoke(del, dr);
 102:  // Reader is to be closed at the end, as some thread may be using it. Use seperate procedure to close it
 103:  }
 104:  catch (Exception ex)
 105:  {
 106:  // We are running the code in a seperate thread so we need to catch the exception. 
 107:  // Else we are unable to catch the exception anywhere.
 108:  this.Invoke(new DisplayStatusDelegate(DisplayStatus), "Error: " + ex.Message);
 109:  }
 110:  finally
 111:  {
 112:  isExecuting = false;
 113:  }
 114:  }
 115:   
 116:  private void Form1_Load(object sender, System.EventArgs e)
 117:  {
 118:  this.btnAsync.Click += new System.EventHandler(this.btnAsync_Click);
 119:  this.FormClosing += new FormClosingEventHandler(Form1_FormClosing);
 120:  }
 121:   
 122:  void Form1_FormClosing(object sender, FormClosingEventArgs e)
 123:  {
 124:  if (isExecuting)
 125:  {
 126:  MessageBox.Show(this, "Ca't close the form until " +
 127:  "the pending asynchronous command has completed. ");
 128:  e.Cancel = true;
 129:  }
 130:   
 131:   

 

Summary

Asynchronous access to the results of multiple commands over the same Connection instance, plus the ability to open connections asynchronously
Main Features
– Ability to switch execution to another thread
– Ability to make calls to network resources in a way that does not block any threads
– Important for high-end 3-tier server applications

Original Source: http://www.csharphelp.com/2007/07/asynchronous-data-access-using-callback-model/

Deepak Kamboj

Deepak Kamboj is a Solution Architect and Technology Enthusiast, located at Redmond, WA, having 14+ years of hands on experience in the IT industry.

You may also like...