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

异步访问长期运行的 Web 服务任务

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.67/5 (2投票s)

2009年4月27日

CPOL

3分钟阅读

viewsIcon

28776

downloadIcon

210

异步访问长期运行的 Web 服务任务

介绍 

我们经常需要处理缓慢而耗时的 Web 服务任务,而使用这些 Web 服务同样令人沮丧。 克服此问题的一种解决方案是以异步方式访问 Web 服务,同时异步运行缓慢而耗时的 Web 服务任务本身。 该解决方案的优点在于它是非阻塞异步调用,并且 UI 不受影响。

使用此方法还可以帮助您维护和管理 Web 服务中的状态。

同样,这可能只是处理此类问题的一种可能性,还有许多其他解决方案。

背景  

我在浏览 ASP.NET 论坛时遇到了这个问题。 我发现这是一个非常有趣的问题,仅仅是因为解决方案可能如此复杂。

当使用缓慢而耗时的服务的客户端发起 Web 服务调用时,web 方法会生成并返回一个 GUID。 使用此 GUID 作为键,我们在 HTTPRuntime 缓存中创建一个条目,并生成一个后台线程来运行缓慢而耗时的任务,完成后,它将使用结果更新 HttpRuntime 缓存条目。

客户端定期轮询 Web 服务以检查缓慢而耗时的任务是否已完成。

使用代码

下载的 zip 文件包含一个 Web 应用程序客户端,该客户端包含一个基于 AJAX 的轮询系统和一个在后台线程中运行任务的 Web 服务。

客户端代码

客户端通过调用 startCalculate web 方法并将其接收到的 id 存储在名为 key 的会话对象中来启动 web 请求。

 protected void Button1_Click(object sender, EventArgs e)
 {
       Session["key"] = sv.startCalculate();
       Lab_Result.Text = "Retrieving the result for ID " + Session["key"].ToString() 
       + " ...";   
 } 

客户端使用 AJAX timer 控件的 Tick 事件进行轮询。 它通过传递存储在名为 key 的会话对象中的 ID 来调用 retrieveValue(string ID)。 如果返回值是“Waiting”或包含“Retrieving”,我将继续轮询结果。 返回结果后,它将不再轮询,从而减少对 Web 服务的不必要调用。

 protected void Timer1_Tick(object sender, EventArgs e)
 {
        if (Session["key"] != null)
        {
              TmpVar = Lab_Result.Text;

              if ((TmpVar == "Waiting!") || (TmpVar.Contains("Retrieving")) || 
              (TmpVar == null))
              {
                  TmpVar = sv.retrieveValue(Session["key"].ToString());
              }

              Lab_Result.Text = TmpVar;
        }
 }  

Web 服务代码

以下 Webservice SlowServiceInMemory 公开了两个 web 方法 startCalculate()retrieveValue(string ID)

startCalculate() 方法生成一个 ID,并将其返回给使用者客户端。 它使用 ID 创建一个 HTTPRuntime 缓存条目,并调用 calculate(string key) 方法,该方法反过来会生成一个后台线程来完成缓慢而耗时的任务。

 [WebMethod]
        public string startCalculate()
        {
            string key = Guid.NewGuid().ToString();
            insertCacheObject(key, "Waiting!");
            calculate(key);
            return key;
        }   

insertCacheObject 方法使用 string 键作为标识符创建缓存条目。

 private void insertCacheObject(string key, string ver)
 {
            HttpRuntime.Cache.Insert(
               key
               , (object)ver
               , null
               , DateTime.Now.AddSeconds(15)
               , Cache.NoSlidingExpiration);
 }

retrieveValue(string key) web 方法检索存储在 HttpRuntime.Cache 条目中的结果,并使用该键。

[WebMethod]
        public string retrieveValue(string key)
        {
            string tmp = "Waiting!";
            try
            {
                tmp = HttpRuntime.Cache.Get(key).ToString();
            }
            catch (Exception ex)
            {
                tmp = "Error " + ex.Message;
            }
            return tmp;
        }

calculate(string key) 方法生成一个后台线程来执行缓慢而耗时的任务。 然后,它将结果存储在缓存条目中。 您可以通过将 Thread.Sleep 值更改为更小或更大的数字来进行进一步的实验。

private void calculate(string key)
{
    Thread th = new Thread(
        delegate()
        {
            Thread.Sleep(10000);
            string Tmp = "Result for long running class!";
            insertCacheObject(key, Tmp);
        });
    th.IsBackground = true;
    th.Start();
}

兴趣点 

您可以扩展此实现,将结果持久保存到数据库或平面文件,而不是缓存。

历史  

  • 2009 年 4 月 27 日:首次发布

我想使用 IAsynchResult 模式实现对 Web 服务的异步调用。 IAsynchResult 模式支持对 Web 服务的异步调用的非阻塞回调实现。

© . All rights reserved.