ASP.NET MVC2 AsyncController:串行执行多个异步操作是否会导致可能的竞争条件?
序言
我们正在实现一个 MVC2 站点,需要通过 https 使用外部 API(恐怕我们不能使用 WCF,甚至不能使用旧式 SOAP WebServices)。无论何时需要与 API 通信,我们都使用 AsyncController
,并且到目前为止一切都运行良好。
在某些情况下,我们需要连续进行多个 API 调用,使用一个步骤的结果来执行下一步。
到目前为止,一般模式(出于演示目的而简化)如下:
public class WhateverController : AsyncController
{
public void DoStuffAsync(DoStuffModel data)
{
AsyncManager.OutstandingOperations.Increment();
var apiUri = API.getCorrectServiceUri();
var req = new WebClient();
req.DownloadStringCompleted += (sender, e) =>
{
AsyncManager.Parameters["result"] = e.Result;
AsyncManager.OutstandingOperations.Decrement();
};
req.DownloadStringAsync(apiUri);
}
public ActionResult DoStuffCompleted(string result)
{
return View(result);
}
}
我们有几个需要并行执行 API 调用的操作已经可以正常工作了;我们只需执行多个请求,并确保正确递增 AsyncManager.OutstandingOperations
。
场景
为了连续执行多个 API 服务请求,我们目前正在为第一个请求的 DownloadStringCompleted
调用事件处理程序中的下一步。例如,
req.DownloadStringCompleted += (sender, e) =>
{
AsyncManager.Parameters["step1"] = e.Result;
OtherActionAsync(e.Result);
AsyncManager.OutstandingOperations.Decrement();
}
其中 OtherActionAsync
是在同一控制器中定义的另一个操作,遵循与上面定义的相同模式。
问题:
访问 AsyncManager
中的值时,从事件处理程序中调用其他异步操作是否会导致可能的竞争?
我尝试查阅 MSDN,但所有关于 AsyncManager.Sync() 的评论都是关于 BeginMethod/EndMethod 模式与 IAsyncCallback 的。在这种情况下,文档会警告潜在的竞争条件。
如果您不喜欢,我们实际上不需要在控制器中调用另一个操作。构建另一个 WebClient
并调用 .DownloadStringAsync()
的代码可以轻松地放置在第一个请求的事件处理程序中。我只是在这里这样展示它,以使其更容易阅读。
希望这是有道理的!如果没有,请发表评论,我会尽力澄清您喜欢的任何内容。
谢谢!
The preamble
We're implementing a MVC2 site that needs to consume an external API via https (We cannot use WCF or even old-style SOAP WebServices, I'm afraid). We're using AsyncController
wherever we need to communicate with the API, and everything is running fine so far.
Some scenarios have come up where we need to make multiple API calls in series, using results from one step to perform the next.
The general pattern (simplified for demonstration purposes) so far is as follows:
public class WhateverController : AsyncController
{
public void DoStuffAsync(DoStuffModel data)
{
AsyncManager.OutstandingOperations.Increment();
var apiUri = API.getCorrectServiceUri();
var req = new WebClient();
req.DownloadStringCompleted += (sender, e) =>
{
AsyncManager.Parameters["result"] = e.Result;
AsyncManager.OutstandingOperations.Decrement();
};
req.DownloadStringAsync(apiUri);
}
public ActionResult DoStuffCompleted(string result)
{
return View(result);
}
}
We have several Actions that need to perform API calls in parallel working just fine already; we just perform multiple requests, and ensure that we increment AsyncManager.OutstandingOperations
correctly.
The scenario
To perform multiple API service requests in series, we presently are calling the next step within the event handler for the first request's DownloadStringCompleted
. eg,
req.DownloadStringCompleted += (sender, e) =>
{
AsyncManager.Parameters["step1"] = e.Result;
OtherActionAsync(e.Result);
AsyncManager.OutstandingOperations.Decrement();
}
where OtherActionAsync
is another action defined in this same controller following the same pattern as defined above.
The question
Can calling other async actions from within the event handler cause a possible race when accessing values within AsyncManager
?
I tried looking around MSDN but all of the commentary about AsyncManager.Sync()
was regarding the BeginMethod/EndMethod pattern with IAsyncCallback
. In that scenario, the documentation warns about potential race conditions.
We don't need to actually call another action within the controller, if that is off-putting to you. The code to build another WebClient
and call .DownloadStringAsync()
on that could just as easily be placed within the event handler of the first request. I have just shown it like that here to make it slightly easier to read.
Hopefully that makes sense! If not, please leave a comment and I'll attempt to clarify anything you like.
Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
事实证明答案是“否”。
(供将来参考,以防有人通过搜索遇到这个问题)
It turns out the answer is "No".
(for future reference incase anyone comes across this question via a search)