C# async/await结合LINQ Select实现CSV导出异常问题
问题核心原因
Select方法传入async委托时,返回值类型是IEnumerable<Task<T>>,你当前代码直接将这个Task集合作为导出结果返回,CSV导出组件遍历数据源时拿到的都是未等待执行的Task对象,反射读取属性时只能读到Task类型自带的Id、Status、AsyncState等属性,完全读不到你封装的业务字段,因此导出的文件没有任何有效内容。

修复代码
使用Task.WhenAll等待所有异步数据查询任务执行完成,拿到实际的匿名对象集合后再返回给导出组件:
private async Task<IEnumerable> OnExport(SearchCriteria cr) { var sr = await GetResult(cr); var results = sr.Results; // 构造所有数据查询任务 var exportQueryTasks = results.Select(async export => { var data = await dataService.GetById(export.Id); var pAddress = export.ContactInformation?.Addresses.FirstOrDefault(x => x.AddressType == Framework.Contracts.Enums.AddressTypes.Physical); var mAddress = export.ContactInformation?.Addresses.FirstOrDefault(x => x.AddressType == Framework.Contracts.Enums.AddressTypes.Mailing); return new { LegalBusinessName = export.Name, DBA = export.DBAName, BusinessEmail = export.ContactInformation?.PrimaryEmail, PhonePrimary = export.ContactInformation?.PrimaryPhone, PhoneTypePrimary = export.ContactInformation?.PrimaryPhoneType, PhoneSecondary = export.ContactInformation?.SecondaryPhone, PhoneTypeSecondary = export.ContactInformation?.SecondaryPhoneType, Website = export.WebAddress, PhysicalStreetAddress = pAddress?.Address1, PhysicalAddressLine2 = pAddress?.Address2, PhysicalCity = pAddress?.City, PhysicalCounty = pAddress?.County, PhysicalState = pAddress?.State, PhysicalZipCode = pAddress?.Zip, MailingStreetAddress = mAddress?.Address1, MailingAddressLine2 = mAddress?.Address2, MailingCity = mAddress?.City, MailingCounty = mAddress?.County, MailingState = mAddress?.State, MailingZipCode = mAddress?.Zip, SchoolOnboarding = data?.ConfirmedVideo, SchoolStartDate = data?.SchoolStartDate, SchoolEndDate = data?.SchoolEndDate, Grades = string.Join(",", data?.GradeLevels.Select(x => x.GradeLevel)), IsReligiousSchool = data?.ConfirmedIsReligious, ReligiousAffiliation = data?.ReligiousAffiliation, TCSignatureName = export.SignatureName, TCDateSigned = export.TermsAcceptedOn }; }); // 等待所有任务执行完成,拿到实际业务数据 var exportData = await Task.WhenAll(exportQueryTasks); return exportData; }
额外注意事项
- 检查
OnExport方法的调用处是否添加了await关键字,如果未await,方法返回的是Task<IEnumerable>对象本身,同样会导致导出组件读不到有效数据。 - 当导出数据量较大时,不建议在循环中逐条调用
GetById查询数据,会产生大量数据库/IO请求,容易触发连接池限制、超时等问题,建议替换为批量查询接口,根据所有Id一次性拉取全量关联数据。 - 多数CSV导出组件不支持自动解析异步任务包装的数据源,传入导出组件的必须是已经执行完成的同步业务数据集合。
内容的提问来源于stack exchange,提问作者blaz0rstack
相关产品推荐
相关产品推荐

