I'm using Blazor Web Assembly and i'm trying to display a Section Header with its Section Content.
int sectionId;
@foreach (var item in Sections)
{
//Display Section Name
<h2>@item.SectionName</h2>
//Get ID For Section Content
sectionId = item.Id;
@foreach (var content in GetContent(sectionId))
{
}
}
But i'm getting the following error on the GetContent(id) Method.
Error - @foreach cannot operate on variable Task because Task<IEnumerable> doesn't contain a public instance
In my component base class, the function is returning a IEnumerable collection of the DTO.
public async Task<IEnumerable<ModuleContentDto>> GetContent(int sectionId)
{
var content = await ModuleService.GetContent(sectionId);
return content;
}
Service Class
public async Task<IEnumerable<ModuleContentDto>> GetContent(int sectionId)
{
var response = await this.httpClient.GetAsync($"api/Module/{sectionId}/GetItems");
try
{
if (response.IsSuccessStatusCode)
{
if (response.StatusCode == System.Net.HttpStatusCode.NoContent)
{
return Enumerable.Empty<ModuleContentDto>();
}
return await response.Content.ReadFromJsonAsync<IEnumerable<ModuleContentDto>>();
}
else
{
var message = await response.Content.ReadAsStringAsync();
throw new Exception($"Http status code: {response.StatusCode} message: {message}");
}
}
catch (Exception)
{
throw;
}
but I cant iterate over the collection in my razor component? Please can someone suggest the best way to do it as iv tried converting to a LIST and a ENumerator.
Thanks, Tom
CodePudding user response:
Your immediate problem is that you do not await
your task. That should be a simple fix.
However, you should really not mix Task
and IEnumerable
. Asyncronous execution and deferred execution in the same method is really a bug waiting to happen. If you want to execute this async
then pick a materialized collection, like a List<>
or simply an array as your return type.
CodePudding user response:
GetContent
is async
and returning a Task
. However, you are calling it without await
in your @foreach
.
You need to call GetContent
in the @code
section of your razor page, for example in OnInitializedAsync()
and store your IEnumerable<ModuleContentDto>
in a variable. Then you can iterate with foreach.
@foreach (var item in Sections)
{
//Display Section Name
<h2>@item.SectionName</h2>
//Get ID For Section Content
@{
int sectionId = item.Id;
}
@if(ModuleContentDtoDict.ContainsKey(sectionId))
{
@foreach (var content in ModuleContentDtoDict[sectionId])
{
}
}
}
@code{
public Dictionary<int, IEnumerable<ModuleContentDto>> ModuleContentDtoDict { get; set; } = new Dictionary<int, IEnumerable<ModuleContentDto>>();
protected override async Task OnInitializedAsync()
{
foreach(var item in Sections)
{
int sectionId = item.Id;
IEnumerable<ModuleContentDto> moduleContentDtoList = await GetContent(sectionId);
ModuleContentDtoDict.Add(sectionId, moduleContentDtoList);
}
}
}