Write For Us

Built-In Asynchronous I/O Support in ASP.NET

Common Scenarios / Built-In Solutions

As we all know, I/O operations is one of the most time consuming operations. In the same time, IO is one of the most needed operations almost in all applications. To make our applications faster and having more responsive user interface, we need to perform those I/O operations asynchronously.


So, this is a common scenario, frequently needed and frequently used.

To make your life easier, many .NET framework classes that provide I/O services come with built-in methods that support and implement the asynchronous execution pattern. This saves you from creating and instantiating delegates to run the I/O operations asynchronously.

In this tutorial we will present the most common I/O scenarios, with their built-in asynchronous execution patterns.

Asynchronous File Access

Accessing a file in your file system, opening it, reading from it, or writing to it, is one of the most time consuming operations, and in the same time is a frequently used operation.

The situation gets worse as the size of your file increase or the number of files to be accessed increase. As usual, to solve this problem we need to use asynchronous execution pattern. Fortunately, this technique is supported in the .NET framework stream classes.

Accessing files is performed by using the "Stream" class. This class is inherited by all other classes that deal with data streams. This object supports the "BeginRead", "BeinWrite", "EndRead", and "EndWrite" methods, that perform the reading or writing operations asynchronously.

One of those classes that inherits the "Stream" class is the "FileStream" class. This class supports the four asynchronous methods mentioned above. We will test this class's asynchronous execution pattern through the following example:

Open Visual Studio 2005. Choose "New / Web Site", and give it a name and location. Now, in the "Default.aspx" design view draw a label control from the Tool Box.

Double click in the page body to activate the "Page_Load" event handler. In the "Default.aspx.vb" type the following code.

    1 Imports System.io
    2 Partial Class _Default
    3     Inherits System.Web.UI.Page
    5     Protected Sub Page_Load(ByVal sender As Object, _
    6      ByVal e As System.EventArgs) Handles Me.Load
    7         ProcessFiles()
    8     End Sub
    9     Public Sub ProcessFiles()
   12         Dim AR As IAsyncResult
   13         Dim FS As New FileStream("c:\File.txt", _
   14          FileMode.Open, FileAccess.Read)
   15         Dim Arr(FS.Length) As Byte
   16         AR = FS.BeginRead(Arr, 0, FS.Length, _
		AddressOf EndRead_Callback, Nothing)
   18         Dim i As Integer
   19         For i = 0 To 10
   20             MsgBox(i.ToString)
   21         Next
   23     End Sub
   24     Public Sub EndRead_Callback(ByVal R As IAsyncResult)
   26         If R.IsCompleted Then
   27             MsgBox("Completed")
   28         End If
   30     End Sub
   31 End Class

As you can see, we first import the "System.IO" namespace. In the "Page_Load" event handler we make a call to a subroutine called "ProcessFiles" from which the asynchronous execution pattern will be carried out. In the "ProcessFiles" subroutine we do the following: We declare an object "AR" of type "IAsyncResult" to hold the state of the asynchronous operation. We then instantiate a file stream object passing to it a file path name, the file mode, and the access mode. Then we declare an array of type "Byte" with a length equal to the length of our file. After that we call the "BeginRead" method of the instantiate file stream object, passing to it the array of bytes we just created as a buffer to read data into, the index of the array at which we begin reading, the maximum number of bytes to read, and the callback method which will be called automatically after the asynchronous operation completes, and an object that can be used to put whatever data you want for this operation. The output of the "BeginRead" method is assigned to the "AR" object.

In the lines from 18 to 21, we created a loop that displays a message box just to test the user interface responsiveness while the asynchronous operation is being carried out. Starting at line 24 we create the callback method, which tests the completion of the operation and displays a message box according to that.

Note: To get a satisfying feeling of the asynchronous reading operation, you will need to choose a file with a length not less than 100 MB. Now run the application and observe the following results: First, the application will display a sequence of message boxes displaying numbers from 0 to 10. Then the label text will be displayed, after a while the message box that indicates operation completeness should popped up. This sequence may vary depending on the length of your file.

As a result, the user interface responsiveness is excellent and the reading asynchronous operation is completed successfully.

To download the complete example, click here.

Asynchronous Remoting

Remoting is a very useful technique you can use to build a widely distributed applications easily. With remoting you can make your application communicate with other processes on the same computer, processor, or on any other computer that is reachable over the network. You can also use it to perform communication with other application domains within the same process.

Asynchronous programming technique in a remoting scenario that is identical to the asynchronous programming technique used within one application domain or context.

As with a single application domain, the asynchronous operation over remoting have the following steps:

  • Create an object with a method that will execute the remote calling procedure, and instantiate it.
  • Define a delegate of type "AsyncDelegate" to the above method.
  • Create a callback method.
  • Define a delegate of type "AsyncCallback" delegate to the above created callback method.
  • Call the "BeginInvoke" method of the first defined delegate to run the method that perform remote calling in asynchronous execution pattern.
  • Do some other different work until your callback method is called.


        Dim RemoteDelegate As New RemoteAsyncDelegate _
         (AddressOf RObj.RemoteMethod)
        Dim RemoteCallbackFun As New AsyncCallback _
         (AddressOf CallbackMethod)
        Dim RAR As IAsyncResult = RemoteDelegate.BeginInvoke _
         (RemoteCallbackFun, Nothing)
        ' Do some other task

As you can observe this is exactly the same procedure we used when we wanted to call any other local method asynchronously.

XML Web Services

In the recent years, the need for interoperability across platforms to connect people, information, and processes has increased. This of course has affected the way software is being developed. Web services comes to this world to satisfy this need. Web services technology is concerned with producing interoperability across platforms. This means that two different platforms can communicate together, each installing an application written by different programming languages and techniques, but all must use the same protocol to be able to communicate together. This communication is done by using the XML universal  language for representing transmitted structured messages and data that is independent of the underlying programming languages, software platforms, and hardware. This is what we call XML web services ...

What concerns us here, is the communication with XML web services asynchronously. This follows the asynchronous design pattern used in the rest of .NET framework.

It is nice to note that: To communicate with an XML web service in asynchronous way, then this does not require this service to be written especially to handle asynchronous calls. The methods that handle asynchronous execution pattern is automatically created by the proxy class you created for your client. For each synchronous method you create, the proxy class automatically creates two methods which are: "Begin...", and "End...", to give you the ability to call the method you created asynchronously when you need to.

Asynchronous Network Communications

Nowadays most applications need the ability to communicate with the network or as we call it: the Internet. Your application can communicate with the network (even it is not an ASP. NET application) using many ways. Some of them are through the "WebRequest" class by which you can request a resource given its URL, or through the "Socket" class which provides a rich set of methods and properties for network communication. These two classes are the most popular classes used in network communications.

As the rest of all .NET framework asynchronous programming model, the "WebRequest" and the "Socket" classes both follow this model. Means that each class have its asynchronous methods. As usual, asynchronous methods always start with the words "Begin....", and "End....".

As an example, to make an asynchronous requests using the "WebRequest" class, instead of using the "GetResponse" method use "BeginGetResponse" and "EndGetResponse" to do the same task asynchronously. This is the only difference between calling the method synchronously or asynchronously, the rest is alike. Of course, you can use callback methods, and all blocking or waiting techniques you usually use with the asynchronous execution pattern.

Both asynchronous client sockets, and asynchronous server sockets follow the .NET framework asynchronous programming model.

For example, with the asynchronous client socket: Instead of using the synchronous "Receive" method, use the asynchronous "BeginReceive", and "EndReceive" methods.

With asynchronous server socket, instead of using the synchronous "Accept" method, use its asynchronous equivalent "BeginAccept", and "EndAccept" methods.

For further information

Refer to the online copy of Microsoft Developers Network at http://msdn.microsoft.com or use your own local copy of MSDN.

Tutorial toolbar:  Tell A Friend  |  Add to favorites  |  Feedback  |