Introduction
Very often we use long running server side transactions/operations where the user is halted for the entire process to be completed. My attempt is to give the user a responsive interaction without much change in their existing application code. It helps developers to do an ongoing long running operation in the server and inform the user when the operation is completed at a later time. The source code contains some independent code files that have to be attached to the existing application and needs little customization in their current application. If you want, you can also use the concept here to do a lot of customization in your code for greater flexibility.
Background
The word transaction used here simply means a long running task on the server due to a database interaction, third party business objects call, using a Web Service, or using a COM component, or any task a lot of time. The user usually waits for a long time for the request to be processed and gets the response from the server regarding information of the generated transaction, even though the transaction status is not required at this point of time. If the user can afford to receive the status of the transaction at a later time when the transaction is completed, then you might use this technique to do the transaction on the server.
Here, I have applied the concept of multithreading using thread pool, Generics in C#, HttpModules, and AJAX. I assume that you have a basic understanding of all these concepts before understanding the article. Let me throw some light on these concepts in brief.
You can initiate a task asynchronously using a CLR thread pool instead of creating a new thread. One way of using thread pools is to use delegates. If you want to execute a function asynchronously, create a delegate whose signature is similar to that of the function and use the delegate's BeginInvoke
method to call the function asynchronously.
Generics in C# lets you to create specific types of collections instead of predefined data types.
Every request from the browser is first passed through all the HttpModules before actually being handled by a Handler. So HttpModules enable you to add application wide functionality.
AJAX lets you do asynchronous communication with the server.
Caution: if the next immediate transaction of the user is very much dependent on the previous transaction, which you cannot afford to have at a later time, then this technique is not the solution.
How it Works
You have a long running transaction on the server and the user waits till the task is completed and the server sends a response to the client after the processing is done. To make the user responsive, the transaction has to be started on a separate thread.
The transaction, here, is started on a separate thread. The transaction is a simple function DoTransactio()
which sleeps for 8 seconds.
private string DoTransaction()
{
try
{
Thread.Sleep(8000);
return (txtTransactionID.Text);
}
catch (Exception)
{
return ("error");
}
}
Now, this is executed on a separate thread, and when the transaction is completed, the appropriate message is added to the transaction information store which is nothing but a generic Dictionary. The dictionary stores the session ID as the key and a Queue as the transaction message. So it ensures for working properly in a multi-user environment. This dictionary is the backbone of the TempDataStore
class which exposes various methods to manipulate the dictionary.
Note : A meaningful transaction message is to be provided by the developer which depends on the type of the work so that the user can understand it, and an appropriate error message has to be provided instead if the transaction is a failure.
private static Dictionary<string,Queue<string>> _table =
new Dictionary<string,Queue<string>>();
When the transaction is completed, an appropriate message is added to the information queue. This is done on the callback method for the delegate.
public void TransactionCallBack(IAsyncResult ar)
{
ArrayList stateArraList = (ArrayList)ar.AsyncState;
string _sessionID = (string)stateArraList[0];
TransactionDel transact = (TransactionDel)stateArraList[1];
string result = transact.EndInvoke(ar);
TransactionReference.TempDataStore.SetRecords(_sessionID, result);
}
And this message is to be thrown to the user when the transaction is completed by using one of two techniques. The first one is through a client side polling using AJAX, and the second one is through a simple postback. Any one of these ensures proper delivery of the transaction information to the user. For achieving this, I used an HttpModule independently, which interacts with every request and through proper user message regarding the transactions. AJAX functionality is achieved by adding the Refresh.js file to the outgoing response. For polling from the client side, I used the setInterval()
method which triggers a function intiateRefresh()
every 5 seconds. It polls the server asynchronously and throws the the transaction status to the user. In case you do a postback or callback to the server, if any transaction is completed, then the appropriate message is shown to the user.
Note: After getting the transaction information from the server, you can customize your own display style instead of the style I have used which shows a simple message box on the client side.
Using the code
The demo application is available along with the source code. To incorporate the functionality within your application, you first need an understanding of the demo application I have provided. Then do the following to add it to your application.
Add TransactionInformationHandler.cs and UserStateStore.cs to your application App_Code directory. Then change the web.config file of the application and add the following lines:
< !--Add this httpModule information here [Customisation]-- >
< httpModules >
< add name="TransactionInformationModule"
type="TransactionInformationModule, App_code" / >
< /httpModules >
You can also make an assembly out of both of these files and add it to your project and use the assembly name, with the proper file extension, in httpModule
instead of App_Code
. Don't forget to include the Refresh.js file within the application. This file contains the code that enables your application to use AJAX functionality.
Identify the task, which is in form of a function, that has to be executed on a separate thread. Create a delegate whose signature is similar to that of the function and use the delegate's BeginInvoke
method to call the function asynchronously. In the callback method of the function, add the appropriate message to the transaction datasource using the method SetRecord(string,string)
of TempdataStore
. Use your own customisation for showing the message to the user by modifying the TransactionInformationHandler.cs file and the Refresh.js file. Or you can also use alternative techniques to retrieve data from TempDataSource
and customise your own style of displaying data to the user.
Change the Global.asax file so that when the session ends, the corresponding Transaction data from the DataSource is cleared.
Conclusion
It helps the user to execute transactions on the server at the same time without waiting for the response to be completed, and the user does it's usual work. When the server does the processing, then the result of the transaction is shown to the user. It makes the application more interactive like a desktop application. The source code provided can be used without much customization in your application as directed above.