[英]await returns before task completes
I have this async code 我有这个异步代码
private async Task<InvalidInvoiceViewModel> ValidateInsertedDataInRawTables(string uploadPath, long batchId)
{
var direcotryPath = Path.Combine(uploadPath, batchId.ToString());
var allFiles = Directory.GetFiles(direcotryPath);
var invoiceRawList = new List<InvoiceRaw>();
var invoiceDetailRawList = new List<InvoiceDetailRaw>();
await Task.Run(() => allFiles.ToList().ForEach(async file =>
{
var fileName = Path.GetFileNameWithoutExtension(file);
switch (fileName)
{
case "invoice":
invoiceRawList = await ValidateInsertedDataInRawTablesForInvoiceAsync(batchId);
break;
case "invoicedetails":
invoiceDetailRawList = await ValidateInsertedDataInRawTablesForInvoiceDetailAsync(batchId);
break;
}
}));
var invalidInvoiceViewModel = new InvalidInvoiceViewModel
{
InvoiceRawList = invoiceRawList ,
InvoiceDetailRawList = invoiceDetailRawList
};
return invalidInvoiceViewModel;
}
But what happens is, the I always get 0 count in both the InvoiceRawList
and InvoiceDetailRawList
. 但是发生的是,我在
InvoiceRawList
和InvoiceDetailRawList
总是得到0计数。 What I found is that the method returns before the async lambda completes its processing. 我发现该方法在异步lambda完成其处理之前返回。 (In chrome console, the result appears in the network tab, but the debug point in
ValidateInsertedDataInRawTablesForInvoiceAsync
is hit after that). (在chrome控制台中,结果显示在“网络”标签中,但是此后会在
ValidateInsertedDataInRawTablesForInvoiceAsync
中点击调试点)。 I am awaiting the Task.Run
that I created for this lambda. 我正在等待为此lambda创建的
Task.Run
。 What am I doing wrong here? 我在这里做错了什么?
Update after comments 评论后更新
If I do that, it won't compile, I changed it to... 如果这样做,它将无法编译,因此将其更改为...
private async Task<InvalidInvoiceViewModel> ValidateInsertedDataInRawTables(string uploadPath, long batchId)
{
var direcotryPath = Path.Combine(uploadPath, batchId.ToString());
var allFiles = Directory.GetFiles(direcotryPath);
var invoiceRawList = new List<InvoiceRaw>();
var invoiceDetailRawList = new List<InvoiceDetailRaw>();
await Task.Run(async () => await allFiles.ToList().ForEach(async file =>
{
var fileName = Path.GetFileNameWithoutExtension(file);
switch (fileName)
{
case "invoice":
invoiceRawList = await ValidateInsertedDataInRawTablesForInvoiceAsync(batchId);
break;
case "invoicedetails":
invoiceDetailRawList = await ValidateInsertedDataInRawTablesForInvoiceDetailAsync(batchId);
break;
}
}));
var invalidInvoiceViewModel = new InvalidInvoiceViewModel
{
InvoiceRawList = invoiceRawList ,
InvoiceDetailRawList = invoiceDetailRawList
};
return invalidInvoiceViewModel;
}
And says cannot await void. 并说不能等待虚无。 Which I know what that means, but then how do I resolve that?
我知道这意味着什么,但是我该如何解决呢? List.ForEach is a void method.
List.ForEach是一个无效方法。
You actually want to wait for WHEN ALL of the inner tasks are finished. 您实际上要等待所有内部任务完成。
Task.WhenAll
is your friend in this case. Task.WhenAll
在这种情况下是您的朋友。
private async Task<InvalidInvoiceViewModel> ValidateInsertedDataInRawTables(string uploadPath, long batchId)
{
var direcotryPath = Path.Combine(uploadPath, batchId.ToString());
var allFiles = Directory.GetFiles(direcotryPath);
var invoiceRawList = new List<InvoiceRaw>();
var invoiceDetailRawList = new List<InvoiceDetailRaw>();
List<Task> tasks = allFiles.Select(file => Task.Run(async () =>
{
var fileName = Path.GetFileNameWithoutExtension(file);
switch (fileName)
{
case "invoice":
invoiceRawList = await ValidateInsertedDataInRawTablesForInvoiceAsync(batchId);
break;
case "invoicedetails":
invoiceDetailRawList = await ValidateInsertedDataInRawTablesForInvoiceDetailAsync(batchId);
break;
}
})).ToList();
await Task.WhenAll(tasks);
var invalidInvoiceViewModel = new InvalidInvoiceViewModel
{
InvoiceRawList = invoiceRawList,
InvoiceDetailRawList = invoiceDetailRawList
};
return invalidInvoiceViewModel;
}
You will have to use regular foreach loop if you want to use await inside it. 如果要在其中使用await,则必须使用常规的foreach循环。
private async Task<InvalidInvoiceViewModel> ValidateInsertedDataInRawTables(string uploadPath, long batchId)
{
var direcotryPath = Path.Combine(uploadPath, batchId.ToString());
var allFiles = Directory.GetFiles(direcotryPath);
var invoiceRawList = new List<InvoiceRaw>();
var invoiceDetailRawList = new List<InvoiceDetailRaw>();
await Task.Run(async () =>
{
foreach(var file in allFiles)
{
var fileName = Path.GetFileNameWithoutExtension(file);
switch (fileName)
{
case "invoice":
invoiceRawList = await ValidateInsertedDataInRawTablesForInvoiceAsync(batchId);
break;
case "invoicedetails":
invoiceDetailRawList = await ValidateInsertedDataInRawTablesForInvoiceDetailAsync(batchId);
break;
}
}
});
var invalidInvoiceViewModel = new InvalidInvoiceViewModel
{
InvoiceRawList = invoiceRawList,
InvoiceDetailRawList = invoiceDetailRawList
};
return invalidInvoiceViewModel;
}
By the way, this code does not make much sense, you are creating invoiceRawList
and invoiceDetailRawList
just to replace them in every iteration of the loop. 顺便说一句,这段代码没有多大意义,您正在创建
invoiceRawList
和invoiceDetailRawList
只是在循环的每次迭代中替换它们。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.