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






2.67/5 (2投票s)
异步访问长期运行的 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 服务的异步调用的非阻塞回调实现。