Monday, December 31, 2007

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

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

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
    4 
    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()
   10 
   11 
   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)
   17 
   18         Dim i As Integer
   19         For i = 0 To 10
   20             MsgBox(i.ToString)
   21         Next
   22 
   23     End Sub
 
   24     Public Sub EndRead_Callback(ByVal R As IAsyncResult)
   25 
   26         If R.IsCompleted Then
   27             MsgBox("Completed")
   28         End If
   29 
   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.





Related articles:

1. Multithreading in ASP.NET
2. Manual Threading in ASP.NET 2.0
3. Use Asynchronous Execution Pattern in ASP.NET
4. .NET Application Domains
5. Interoperating with Unmanaged Code - PInvoke