我遇到需要调用Web服务的情况,并且在成功完成后,使用Web服务返回的结果执行多项操作。我已经开发了“#34;工作" - 就像我没想的那样。具体来说,我想从调用Web服务获取结果并将这些结果传递给要并行执行的多个连续任务,但是我现在所做的事情在开始第二个任务之前执行第一个连续任务。
我已经汇总了一个简单的例子,说明了我目前正在做的事情,并希望有助于说明这种情况。首先,实施:
public interface IConfigurationSettings
{
int? ConfigurationSetting { get; set; }
}
public interface IPrintCommandHandler
{
System.Threading.Tasks.Task<bool> ExecuteAsync(byte[] reportContent);
}
public interface ISaveCommandHandler
{
System.Threading.Tasks.Task<bool> ExecuteAsync(byte[] reportContent);
}
public interface IWebService
{
System.Threading.Tasks.Task<object> RetrieveReportAsync(string searchToken, string reportFormat);
}
public class ReportCommandHandler
{
private readonly IConfigurationSettings _configurationSettings;
private readonly IPrintCommandHandler _printCommandHandler;
private readonly ISaveCommandHandler _saveCommandHandler;
private readonly IWebService _webService;
public ReportCommandHandler(IWebService webService, IPrintCommandHandler printCommandHandler, ISaveCommandHandler saveCommandHandler, IConfigurationSettings configurationSettings)
{
_webService = webService;
_printCommandHandler = printCommandHandler;
_saveCommandHandler = saveCommandHandler;
_configurationSettings = configurationSettings;
}
public async Task<bool> ExecuteAsync(string searchToken)
{
var reportTask = _webService.RetrieveReportAsync(searchToken, "PDF");
var nextStepTasks = new List<Task<bool>>();
// Run "print" task after report task.
var printTask = await reportTask.ContinueWith(task => _printCommandHandler.ExecuteAsync((byte[]) task.Result));
nextStepTasks.Add(printTask);
// Run "save" task after report task.
if (_configurationSettings.ConfigurationSetting.HasValue)
{
var saveTask = await reportTask.ContinueWith(task => _saveCommandHandler.ExecuteAsync((byte[]) task.Result));
nextStepTasks.Add(saveTask);
}
var reportTaskResult = await Task.WhenAll(nextStepTasks);
return reportTaskResult.Aggregate(true, (current, result) => current & result);
}
}
因此,Web服务(第三方,与我无关)有一个端点用于执行搜索/查找,如果成功,则返回一个参考号(在我的示例中,我称之为搜索令牌) )。然后使用此参考编号以几种不同格式检索查找结果(使用不同的端点)。
此示例中的IWebService
接口代表我为管理与Web服务的交互而创建的应用程序服务。实际的实现还有其他方法可以进行查找,ping等。
只是为了让事情变得更有趣,需要一个连续的任务(将始终在主要任务之后执行),但另一个连续任务是可选的,执行受设置中其他地方设置的配置设置的限制。
为了更容易地证明这个问题,我创建了一个单元测试:
public class RhinoMockRepository : IDisposable
{
private readonly ArrayList _mockObjectRepository;
public RhinoMockRepository()
{
_mockObjectRepository = new ArrayList();
}
public T CreateMock<T>() where T : class
{
var mock = MockRepository.GenerateMock<T>();
_mockObjectRepository.Add(mock);
return mock;
}
public T CreateStub<T>() where T : class
{
return MockRepository.GenerateStub<T>();
}
public void Dispose()
{
foreach (var obj in _mockObjectRepository) obj.VerifyAllExpectations();
_mockObjectRepository.Clear();
}
}
[TestFixture]
public class TapTest
{
private const string SearchToken = "F71C8B50-ECD1-4C02-AD3F-6C24F1AF3D9A";
[Test]
public void ReportCommandExecutesPrintAndSave()
{
using (var repository = new RhinoMockRepository())
{
// Arrange
const string reportContent = "This is a PDF file.";
var reportContentBytes = System.Text.Encoding.Default.GetBytes(reportContent);
var retrieveReportResult = System.Threading.Tasks.Task.FromResult<object>(reportContentBytes);
var webServiceMock = repository.CreateMock<IWebService>();
webServiceMock.Stub(x => x.RetrieveReportAsync(SearchToken, "PDF")).Return(retrieveReportResult);
var printCommandHandlerMock = repository.CreateMock<IPrintCommandHandler>();
var printResult = System.Threading.Tasks.Task.FromResult(true);
printCommandHandlerMock
.Expect(x => x.ExecuteAsync(reportContentBytes))
//.WhenCalled(method => System.Threading.Thread.Sleep(TimeSpan.FromSeconds(2)))
.Return(printResult);
var configurationSettingsStub = repository.CreateStub<IConfigurationSettings>();
configurationSettingsStub.ConfigurationSetting = 10;
var saveCommandHandlerMock = repository.CreateMock<ISaveCommandHandler>();
var saveResult = System.Threading.Tasks.Task.FromResult(true);
saveCommandHandlerMock.Expect(x => x.ExecuteAsync(reportContentBytes)).Return(saveResult);
// Act
var reportCommandHandler = new ReportCommandHandler(webServiceMock, printCommandHandlerMock, saveCommandHandlerMock, configurationSettingsStub);
var result = System.Threading.Tasks.Task
.Run(async () => await reportCommandHandler.ExecuteAsync(SearchToken))
.Result;
// Assert
Assert.That(result, Is.True);
}
}
}
理想情况下,完成对RetrieveReportAsync()
IWebService
的调用后,&#34;打印&#34;并且&#34;保存&#34;在收到RetrieveReportAsync()
的结果副本后,应同时执行命令处理程序。但是,如果单元测试中对WhenCalled
...的调用已取消注释,并且逐步执行ReportCommandHandler.ExecuteAsync()
,则可以看到&#34; print&#34;命令在到达&#34; save&#34;之前执行并完成。命令。现在,我知道await
的重点是暂停执行调用async
方法,直到await
ed代码完成,但我不清楚如何实例化&#34; print&#34;并且&#34;保存&#34;命令(任务)作为&#34;报告的延续&#34;任务使得它们在&#34;报告&#34;任务完成,&#34;报告&#34;然后命令可以返回基于&#34; print&#34;的结果的结果。并且&#34;保存&#34;命令(任务)。
答案 0 :(得分:2)
您的问题实际上涉及两个不同的目标:
我发现代码中import LinearGradient from 'react-native-linear-gradient'
和await
的混合令人困惑。我不明白为什么你这样做。 ContinueWith()
为您做的一件重要事情是自动设置延续,因此您不必明确调用await
。然而,无论如何,你做了。
假设这只是一个错误,由于缺乏对如何实现目标的充分理解,这就是我如何编写你的方法:
ContinueWith()
换句话说,首先执行public async Task<bool> ExecuteAsync(string searchToken)
{
var reportTaskResult = await _webService.RetrieveReportAsync(searchToken, "PDF");
var nextStepTasks = new List<Task<bool>>();
// Run "print" task after report task.
var printTask = _printCommandHandler.ExecuteAsync((byte[]) reportTaskResult);
nextStepTasks.Add(printTask);
// Run "save" task after report task.
if (_configurationSettings.ConfigurationSetting.HasValue)
{
var saveTask = _saveCommandHandler.ExecuteAsync((byte[]) reportTaskResult);
nextStepTasks.Add(saveTask);
}
var reportTaskResult = await Task.WhenAll(nextStepTasks);
return reportTaskResult.Aggregate(false, (current, result) => current | result);
}
原始任务。然后你知道它已经完成并得到了它的结果。那时,继续开始其他任务,将他们的await
对象添加到您的列表中,但不等待每个任务。最后,Task
整个任务列表。