65.9K
CodeProject 正在变化。 阅读更多。
Home

使用ASP.NET AJAX尝试进行异步事务

starIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIconemptyStarIcon

1.83/5 (6投票s)

2007年5月28日

CPOL

6分钟阅读

viewsIcon

32518

downloadIcon

179

让耗时长的事务更容易管理。

引言

我们经常会遇到耗时长的服务器端事务/操作,在此期间用户将被阻塞,直到整个过程完成。我的尝试是在不更改现有应用程序代码太多内容的情况下,为用户提供响应式交互。它帮助开发人员在服务器上执行一个正在进行的耗时操作,并在稍后通知用户操作已完成。源代码包含一些独立的代码文件,需要将其附加到现有应用程序中,并需要对当前应用程序进行一些小的定制。如果愿意,您还可以利用此处的概念,对代码进行大量定制以获得更大的灵活性。

背景

此处使用的事务一词仅指服务器上的长时间运行任务,可能是由于数据库交互、第三方业务对象调用、使用 Web 服务、使用 COM 组件或任何耗时任务。用户通常需要等待很长时间才能处理请求并从服务器获取有关生成的事务信息的响应,即使此时不需要事务状态。如果用户可以在事务完成后稍后接收事务状态,那么您可以使用此技术在服务器上执行事务。

在此,我应用了多线程(使用线程池)、C# 中的泛型、HttpModules 和 AJAX 的概念。我假设您在理解本文之前已经对所有这些概念有了基本的了解。让我简要地阐述一下这些概念。

您可以使用 CLR 线程池而不是创建新线程来异步启动任务。使用线程池的一种方法是使用委托。如果您想异步执行一个函数,请创建一个签名与该函数相似的委托,并使用该委托的 BeginInvoke 方法异步调用该函数。

C# 中的泛型允许您创建特定类型的集合,而不是预定义的简单数据类型。

从浏览器发出的每个请求在实际由处理程序处理之前,都会先经过所有的 HttpModules。因此 HttpModules 使您能够添加应用程序范围的功能。

AJAX 允许您与服务器进行异步通信。

注意: 如果用户的下一个即时事务非常依赖于前一个事务,而您又无法稍后进行处理,那么此技术不是解决方案。

工作原理

您在服务器上有一个耗时长的事务,用户会一直等待直到任务完成,然后在处理完成后服务器向客户端发送响应。为了让用户保持响应,事务必须在一个单独的线程上启动。

事务在这里是在一个单独的线程上启动的。事务是一个简单的函数 DoTransactio(),它会休眠 8 秒。

//Transaction to be executed asynchrounously, here it takes 8 second to be completed  
private string DoTransaction()
{
    try
    {
        Thread.Sleep(8000);
        return (txtTransactionID.Text);
    }
    catch (Exception)
    {
        //Add your custom message for any error in the transaction, i used simple error
        return ("error");
    }
}

现在,这在一个单独的线程上执行,当事务完成后,相应的消息将被添加到事务信息存储中,这只是一个泛型 Dictionary。该字典将会话 ID 作为键,将一个 Queue 作为事务消息。因此,它确保在多用户环境中正常工作。这个字典是 TempDataStore 类的基础,该类公开了各种方法来操作字典。

注意:开发者需要提供有意义的事务消息,这取决于工作的类型,以便用户能够理解它,并且如果事务失败,则必须提供相应的错误消息。

//transaction information datasource
private static Dictionary<string,Queue<string>> _table = 
        new Dictionary<string,Queue<string>>(); 

当事务完成时,会将相应的消息添加到信息队列中。这是在委托的回调方法中完成的。

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);

    //This code has to be added for storing the details
    //of the transaction in our temporary datasource
    TransactionReference.TempDataStore.SetRecords(_sessionID, result); //Added extra code
}

并且这条消息需要通过以下两种技术之一发送给用户,以通知事务已完成。第一种是通过 AJAX 进行客户端轮询,第二种是通过简单的回发。其中任何一种都能确保事务信息能正确传达给用户。为了实现这一点,我独立使用了一个 HttpModule,它与每个请求进行交互,并通过适当的用户消息来传递事务信息。AJAX 功能通过将 Refresh.js 文件添加到传出的响应中来实现。对于从客户端进行轮询,我使用了 setInterval() 方法,该方法每 5 秒触发一次 intiateRefresh() 函数。它会异步轮询服务器并将事务状态发送给用户。如果您在服务器上进行回发或回调,如果任何事务已完成,则会向用户显示相应的消息。

注意:在从服务器获取事务信息后,您可以自定义自己的显示样式,而不是我使用的显示简单消息框的样式。

使用代码

演示应用程序随源代码一起提供。要将此功能集成到您的应用程序中,您首先需要了解我提供的演示应用程序。然后按照以下步骤将其添加到您的应用程序中。

TransactionInformationHandler.csUserStateStore.cs 添加到您的应用程序 App_Code 目录中。然后更改应用程序的 web.config 文件并添加以下行

< !--Add this httpModule information here [Customisation]-- >
< httpModules >
    < add name="TransactionInformationModule" 
          type="TransactionInformationModule, App_code" / >
< /httpModules >

您还可以将这两个文件编译成一个程序集并将其添加到您的项目中,然后在 httpModule 中使用程序集名称(带有正确的文件扩展名)而不是 App_Code。不要忘记将 Refresh.js 文件包含在应用程序中。此文件包含启用您的应用程序使用 AJAX 功能的代码。

识别要在单独线程上执行的任务,该任务以函数的形式存在。创建一个签名与该函数相似的委托,并使用该委托的 BeginInvoke 方法异步调用该函数。在函数的​​回调方法中,使用 TempdataStoreSetRecord(string,string) 方法将相应的消息添加到事务数据源中。通过修改 TransactionInformationHandler.cs 文件和 Refresh.js 文件来显示给用户的消息,使用您自己的定制。或者,您也可以使用其他技术从 TempDataSource 检索数据,并自定义自己的数据展示样式。

更改 Global.asax 文件,以便在会话结束时,从数据源中清除相应的事务数据。

结论

它有助于用户同时在服务器上执行事务,而无需等待响应完成,并且用户可以继续进行正常工作。当服务器完成处理后,事务的结果将显示给用户。这使得应用程序的交互性更强,就像桌面应用程序一样。提供的源代码可以在不进行太多定制的情况下,按照上述指示用于您的应用程序。

© . All rights reserved.