C# 等待背景任务完成
我有一个C# 等待背景任务完成,c#,asynchronous,async-await,windows-10,win-universal-app,C#,Asynchronous,Async Await,Windows 10,Win Universal App,我有一个BackgroundTask,它生成一些文本,然后将其作为文件保存到LocalFolder中。我需要在BackgroundTask生成此文件后,将其与我的主项目(相同的VS解决方案)一起获取,并对其进行一些后续工作。后台任务由用户手动触发(通过“重新加载”按钮),并由TimeTrigger每隔15分钟触发一次 这是相关的代码片段: syncTrigger.RequestAsync(); articles = await getCachedArticles(""); 如何让getCac
BackgroundTask
,它生成一些文本,然后将其作为文件保存到LocalFolder
中。我需要在BackgroundTask
生成此文件后,将其与我的主项目(相同的VS解决方案)一起获取,并对其进行一些后续工作。后台任务由用户手动触发(通过“重新加载”按钮),并由TimeTrigger
每隔15分钟触发一次
这是相关的代码片段:
syncTrigger.RequestAsync();
articles = await getCachedArticles("");
如何让
getCachedArticles
方法在上一个请求完成后再运行?多谢各位 如果希望当前上下文在继续之前等待异步方法完成,则需要使用wait
关键字:
await syncTrigger.RequestAsync(); //the line below will not be executed until syncTrigger.RequestAsync() completes its task
articles = await getCachedArticles("");
我建议您通读以全面了解其工作原理。您需要等待RequestAsync方法完成并获得结果 之后,我建议使用task.delay等待几秒钟,然后尝试获取数据 更新: 当您有设备触发结果时,您需要在尝试获取数据之前检查此结果,然后您可以假设您保存了数据。我之前建议使用Task.Delay,只需等待几秒钟,以确保所有数据都已保存,因为有时该过程所花的时间比预期的要多出几毫秒。我这样做是因为我们没有像TriggerCompleted这样的事件,我需要创建自己的方法。
我以前在我的应用程序中这样做过,效果很好。如果我理解正确,你需要做的就是等待启动 一种方法是创建一个扩展方法,该方法返回一个
任务
,该任务在事件触发时完成:
public static Task<BackgroundTaskCompletedEventArgs> CompletedAsync(
this BackgroundTaskRegistration registration)
{
var tcs = new TaskCompletionSource<BackgroundTaskCompletedEventArgs>();
BackgroundTaskCompletedEventHandler handler = (s, e) =>
{
tcs.SetResult(e);
registration.Completed -= handler;
};
registration.Completed += handler;
return tcs.Task;
}
请注意,代码在调用RequestAsync()
之前调用CompletedAsync()
,以确保在触发任务之前注册偶数处理程序,以避免在注册处理程序之前任务完成时出现争用情况。编辑:显示了最佳方法,我甚至为此编写了一篇文章。下面是我的原始答案,其中包含了一些可能适用于某些情况的间接备选方案
正如其他人所指出的,等待syncTrigger.RequestAsync()
不会有帮助,尽管这是一个好主意。当后台任务成功触发时,它将恢复执行,因此允许您检查它是否因任何原因失败
当您从应用程序触发后台任务时,您可以创建一个脚本使其工作。应用程序服务的行为类似于web服务。它们在后台任务中运行,但具有请求-响应语义
在后台服务中,您需要处理RequestReceived
事件:
public void Run(IBackgroundTaskInstance taskInstance)
{
var details = taskInstance.TriggerDetails as AppServiceTriggerDetails;
appServiceconnection = details.AppServiceConnection;
appServiceconnection.RequestReceived += OnRequestReceived;
}
private async void OnRequestReceived(AppServiceConnection sender,
AppServiceRequestReceivedEventArgs args)
{
var messageDeferral = args.GetDeferral();
ValueSet arguments = args.Request.Message;
ValueSet result = new ValueSet();
// read values from arguments
// do the processing
// put data for the caller in result
await args.Request.SendResponseAsync(result);
messageDeferral.Complete();
}
然后,您可以在客户端调用应用程序服务:
var inventoryService = new AppServiceConnection();
inventoryService.AppServiceName = "from manifest";
inventoryService.PackageFamilyName = "from manifest";
var status = await inventoryService.OpenAsync();
var arguments = new ValueSet();
// set the arguments
var response = await inventoryService.SendMessageAsync(arguments);
if (response.Status == AppServiceResponseStatus.Success)
{
var result = response.Message;
// read data from the result
}
有关应用程序服务的更多信息,请查看
您也可以从计划的后台任务调用相同的应用程序服务,但在本例中,处理完成时无法获得通知
由于您提到您正在通过LocalFolder
中的文件交换数据,您的应用程序可以尝试监视对该文件的更改
private async Task Init()
{
var storageFolder = ApplicationData.Current.LocalFolder;
var monitor = storageFolder.CreateFileQuery();
monitor.ContentsChanged += MonitorContentsChanged;
var files = await monitor.GetFilesAsync();
}
private void MonitorContentsChanged(IStorageQueryResultBase sender, object args)
{
// react to the file change - should mean the background task completed
}
据我所知,您只能监视文件夹中的所有更改,无法确定事件处理程序中发生了什么更改,因此对于您的情况,最好有一个单独的子文件夹,其中只包含后台任务完成后保存的文件。这样,只有在需要时才会引发事件
不过,您必须自己检查此方法是否足够可靠。如果我正确理解您的问题,您希望
getCachedArticles(“”
仅在syncTrigger.RequestAsync()完成后运行?对吗?没错。如果我的解释不是最好的,请原谅——我不是每天都说英语的人。:)没问题!只是想确定我理解了这个问题。我也不是母语人士,我理解这场斗争。你能展示一下RequestAsync
和getCachedArticles
的签名吗?对于getCachedArticles()
来说,它是私有异步任务getCachedArticles(string sourceName)
。不幸的是,即使是“等待”也没有改变。我在articles=await-getCachedArticles(“”)上有断点
和我正在使用syncTrigger.RequestAsync()调用的BackgroundTask中,在请求调用之前执行getCachedArticles()
。RequestAsync
方法的方法签名是什么?非常奇怪的是,articles=…
行应该运行--await syncTrigger…
应该完全阻止这种情况,至少在它运行完之前是这样。我也希望如此。对不起,您所说的“方法签名”是什么意思?syncTrigger是一个DeviceTriggerResult
?我所说的方法签名是指,例如public returnType methodName(var input1,var input2)
。问题是,它会等到触发请求完成,而不是任务执行完成。你真的应该回去更改你的应用程序。我认为这根本不是一个非常可靠的解决方案。目前还没有一个可靠的解决方案。我真的很高兴看到你最后一次提到的观点——变更监控。我会试试……:)剩下的部分似乎太复杂了——我对UWP和C#都是新手。谢谢,你忽略了吗?或者你是说这是错的?@svick我认为你的答案不适用于每15分钟自动触发一次的预定任务?@DamirArh为什么不?它仍然是同一个后台任务,只是一个不同的触发器,因此相同的BackgroundTaskRegistration
应该对两者都有效。@svick-Hm。。。只要您在应用程序启动时重新注册它,并附加一个新的事件处理程序(无论如何,这都是一个好主意),它就确实可以工作。当然,TaskCompletionSourc
private async Task Init()
{
var storageFolder = ApplicationData.Current.LocalFolder;
var monitor = storageFolder.CreateFileQuery();
monitor.ContentsChanged += MonitorContentsChanged;
var files = await monitor.GetFilesAsync();
}
private void MonitorContentsChanged(IStorageQueryResultBase sender, object args)
{
// react to the file change - should mean the background task completed
}