Retrieving Data: From Synchronous to Asynchronous

As technology keeps moving on, we as developers are continually challenged to learn new ways of doing our jobs. Many years ago (starting as far back as Visual Basic 4.0) the movement was toward OOP and creating N-Tier applications. This meant wrapping up the data returned from DAO, RDO or ADO into classes and collections of classes. .NET came along and we started using ADO.NET to retrieve data. However, usage of classes and collection classes changed very little, at least conceptually. In .NET 2.0 Generics were introduced, but this just helped simplify our code. Again, our basic class structure changed very little.

If you were a normal desktop developer (Windows Forms) or an ASP.NET developer you were able to simply connect to your database, retrieve your data, and life was good. However, as more devices have exploded into our world, we are forced to learn new ways to consume our data. Most prevalent is the use of web services or Service Oriented Architecture (SOA). Luckily, web services can be consumed from desktop apps, web apps, and mobile apps. If you are doing desktop apps and web apps, you can most likely consume these services using a synchronous model. If you are using Silverlight, HTML5 with JS or other mobile applications, you will have to use an asynchronous model. Moving from synchronous to asynchronous is not too difficult; it just takes a little different style of programming.

The Product Class

In the sample code you will be using a Product class. This class has just four properties and is used to store a single product. This class is shown below:

public class Product
{  
  public int ProductId { get; set;}
  public string ProductName { get; set; }
  public DateTime IntroductionDate { get; set; }
  public decimal Price { get; set; }
}

You can then create a collection of Product objects using a generic List<Product>. Of course you can use any method you want for creating a collection of Product objects.

Create a Collection of Products

The code to create a collection of Product objects has not fundamentally changed in years. In the code below I will use ADO.NET to just keep things simple. Feel free to use LINQ to SQL, the Entity Framework, or any other method you want. Just realize that under the hood, all of these technologies perform this same type of code.

using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;

public List<Product>  GetProducts()
{
  List<Product> ret = new List<Product>();
  DataTable dt = new DataTable();
  SqlDataAdapter da;

  da = new SqlDataAdapter("SELECT * FROM Product",
      ConfigurationManager.ConnectionStrings["Sandbox"].
        ConnectionString);

  da.Fill(dt);

  foreach (DataRow item in dt.Rows)
  {
    Product prod = new Product();

    prod.ProductId = Convert.ToInt32(item["ProductId"]);
    prod.ProductName = Convert.ToString(item["ProductName"]);
    prod.IntroductionDate =
       Convert.ToDateTime(item["IntroductionDate"]);
    prod.Price = Convert.ToDecimal(item["Price"]);

    ret.Add(prod);
  }

  return ret;
}

In the code above you create a SqlDataAdapter object which is used to fill up a DataTable. You iterate over the rows in the DataTable and create an instance of a Project class. You fill each property of the Product object with the corresponding data from the column you retrieved from the Product table. This new Product object is added to the collection class. Again, this type of code has not changed in over 15 years. You would have written very similar code in Visual Basic, as far back as version4.0.

Accessing Data Directly (The Old Way)

From a Windows Forms, WPF or ASP.NET application you can use the above code directly from your front end to load data into a list box or other list-type control. In the sample code you can download with this article, there is a user control with a Load Products (Local) button (Figure 1).

Figure 1: Samples to load Product Data

Figure 1: Samples to load Product Data

When you click on this button you run the following code:

private void btnLoad_Click(object sender, RoutedEventArgs e)
{
  List<Product> coll;

  try
  {
    coll = GetProducts();

    lstData.DataContext = coll;
  }
  catch (Exception ex)
  {
    MessageBox.Show(ex.Message);
  }
}

In this click event you simply call the GetProducts() method directly in a synchronous manner. While this is fine for a normal desktop application, if you wish to use this code in Silverlight, Windows Phone, Windows 8 Metro, or any of the other mobile devices you will need to use a service. To start this process, let’s take a look at how to create a service using WCF and then call this service synchronously. Later in this article you will then call this same WCF service asynchronously.

Accessing Data Synchronously From a Web Service

Creating a service application is very easy in  Visual Studio. You simply choose New Project and select WCF from the list of installed templates. Choose the WCF Service application from the list of template projects. Give this new service project a name of ProductService. Next, delete the IService.cs and Service.svc files. It is easier to delete and just add a new name than to rename the files and classes. Now add a new WCF Service called ProductService. This creates two new files in your project; IProductService.cs and ProductService.svc. Into the IProductService interface you will define a contract that specifies a method name and the return value from that method.

[ServiceContract]
public interface IProductService
{
  [OperationContract]
  List<Product> GetProducts();
}

In the code behind of the ProductService.svc you will then drop in the GetProducts() method you wrote before. You will need to add a <connectionStrings> element in the Web.config file that the service can use to connect to the database where your product data resides.

Back in your client code, you now need to add a Service Reference to your WCF service. Name this service ProductSyncServiceReference. In the sample for this article, which is named SyncToASync, you will then need a using statement to use the classes in the namespace created by the Service Reference dialog.

using SyncToASync.ProductSyncServiceReference;

Next, you write code under the Load button’s click event procedure to call the GetProducts method in this WCF service. The generated code creates a class called ProductServiceClient that knows how to connect to your service endpoint. You will create an instance of this class and call the GetProducts method as shown in the code below.

private void btnLoad_Click(object sender, RoutedEventArgs e)
{
  List<Product> ret;
  ProductServiceClient productService =
    new ProductServiceClient();

  try
  {
    ret = productService.GetProducts();
    productService.Close();

    lstData.DataContext = ret;
  }
  catch (Exception ex)
  {
    MessageBox.Show(ex.Message);
  }
}

This code calls the WCF service, the service gathers the data, and then the collection of Product objects is returned from the service. All of this happens synchronously, which means that until the service calls finishes your code and UI are frozen on this one line of code.

Let’s now look at how to make this call asynchronously and thus free up your UI and other code to run while the code to fetch the data waits for the data from the service.

Accessing Data Asynchronously From a Service

You can call this same WCF Service asynchronously from your WFP, Windows Forms or ASP.NET application (as well as Silverlight and Windows Phone). When you create the service reference in your WPF application you will need to click on the Advanced… button (Figure 2) to specify that you wish to generate asynchronous method calls (Figure 3). You do not need to do this step with Silverlight and Windows Phone as this dialog knows that the only option is asynchronous in these environments.

It is a good idea to also choose System.Collections.Generic.List in the Advanced dialog. What this option does is to map any List<T> objects that you return from your WCF service are returned as a generic collection. By default, WCF services will return an array because that is more usable by other consumers other than .NET. Since we are using .NET, we can take advantage of Generics.

Figure 2: Click the Advanced Button to create asynchronous code

Figure 2: Click the Advanced Button to create asynchronous code

Figure 3: Change the async and collection types

Figure 3: Change the async and collection types

Now in your client side code, you will again need to add a using statement to bring in the namespace for the asynchronous web service reference.

using SyncToASync.ProductAsyncServiceReference;

Now you write your code in the Click event for your button. This code will be different from the synchronous version of this code. First you need to create an instance of the ProductServiceClient outside of any event procedures in your window as shown below:

ProductServiceClient _ProductService =
  new ProductServiceClient();

You need the variable that points to the ProductServiceClient to be defined as a field in your C# class because you need to call a method on this object in one method, but you will need to close the connection through this object in another method. Thus, you need to define this variable at the class level so all methods and events in this class can use this variable.

When you clicked on the “Generate asynchronous operations” check box this causes the code generator to create a “Completed” event and a “GetProductsAsync()” procedure. You first hook up an event procedure to call back into after the data has been gathered asynchronously and returned back to the client. Next you call the GetProductsAsync method to start the asynchronous process of gathering the data in the background.

private void btnLoad_Click(object sender, RoutedEventArgs e)
{
  _ProductService.GetProductsCompleted += new
         EventHandler<GetProductsCompletedEventArgs>
            (client_GetProductsCompleted);

  _ProductService.GetProductsAsync();
}

In the “Completed” event procedure you will get an event argument that contains a “Result” property. In this property is the return value from the call to your web service. In this case it is a generic List collection of Product objects. You can take that data and put it into the DataContext property of your list box. If you have bound your list box correctly, then the product data will be displayed after the call to the Completed event is finished. At this point you should also close the connection to the Product service.

void client_GetProductsCompleted(object sender,
 GetProductsCompletedEventArgs e)
{     
  lstData.DataContext = e.Result;

  _ProductService.Close();
}

Summary

Asynchronous programming will become more and more prevalent with Windows 8 as that will be the only supported model for most of the APIs and certainly for any Metro-style application. You can start learning and using Asynchronous programming today and prepare for the future. Start slowly by adding a few calls to a service from your existing applications. Have fun!

NOTE: You can download this article and many samples like the one shown in this blog entry at my website. http://www.pdsa.com/downloads. Select “Tips and Tricks”, then “Synchronous to Asynchronous Data” from the drop down list.

Good Luck with your Coding,
Paul Sheriff

** SPECIAL OFFER FOR MY BLOG READERS **
We frequently offer a FREE gift for readers of my blog. Visit http://www.pdsa.com/Event/Blog for your FREE gift!

Past Blog Content

Blog Archive

No Comments