Преамбула
Мы внедряем сайт MVC2, который должен использовать внешний API через https (боюсь, мы не можем использовать WCF или даже SOAP WebServices старого стиля). Мы используем AsyncController
везде, где нам нужно для связи с API, и пока все работает нормально.
В некоторых сценариях нам нужно делать несколько последовательных вызовов 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()
, который можно так же легко поместить в обработчик событий первого запроса. Я только что показал это здесь, чтобы его было легче читать.
Надеюсь, это имеет смысл! Если нет, пожалуйста, оставьте комментарий, и я постараюсь уточнить все, что вам нравится.
Спасибо!