我一直在使用Blazor和C#8.0中的IAsyncEnumerable功能。是否可以使用IAsyncEnumerable并在Razor页面中等待以逐步显示带有数据的标记?
示例服务:
private static readonly string[] games = new[] { "Call of Duty", "Legend of Zelda", "Super Mario 64" };
public async IAsyncEnumerable<string> GetGames()
{
foreach (var game in games)
{
await Task.Delay(1000);
yield return game;
}
}
剃须刀页面中的示例:
@await foreach(var game in GameService.GetGames())
{
<p>@game</p>
}
这将导致错误CS4033:'await'运算符只能在异步方法中使用。考虑使用“异步”修饰符标记该方法,并将其返回类型更改为“任务”。
有什么可能的想法吗?
答案 0 :(得分:5)
服务器端Razor允许您描述。 This video描述了this Github repo中的代码,该代码展示了如何通过修改服务器端Blazor模板中的<givenName>JOHN</givenName>
<surname>DOE</surname>
<givenName>JANE</givenName>
<surname>DOE</surname>
示例来使用IAsyncEnumerable。
修改服务本身很容易,实际上可以产生更简洁的代码:
ForecastService
另一方面,“ Blazor”页面更为复杂。不仅仅是循环必须在显示HTML之前完成,您不能在页面本身中使用 public async IAsyncEnumerable<WeatherForecast> GetForecastAsync(DateTime startDate)
{
var rng = new Random();
for(int i=0;i<5;i++)
{
await Task.Delay(200);
yield return new WeatherForecast
{
Date = startDate.AddDays(i),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
};
}
}
是因为它不是异步的。您只能在代码块中定义异步方法。
您可以做的是枚举IAsyncEnumerable,并在每次更改后通知页面刷新自身。
渲染代码本身不需要更改:
await foreach
<table class="table">
<thead>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in forecasts)
{
<tr>
<td>@forecast.Date.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
在收到每个项目后需要致电OnInitializeAsync
:
StateHasChanged()
在问题的示例中,传入的游戏可以存储在列表中,而渲染代码保持不变:
List<WeatherForecast> forecasts;
protected override async Task OnInitializedAsync()
{
forecasts =new List<WeatherForecast>();
await foreach(var forecast in ForecastService.GetForecastAsync(DateTime.Now))
{
forecasts.Add(forecast);
this.StateHasChanged();
}
}
答案 1 :(得分:3)
您无法在await foreach
模板代码上编写.razor
。但是,作为解决方法,您可以在@code
部分中编写它:
@if (@gamesUI == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table">
<thead>
<tr>
<th>Game</th>
</tr>
</thead>
<tbody>
@foreach (var game in gamesUI) // <--- workaround
{
<tr>
<td>@game</td>
</tr>
}
</tbody>
</table>
}
@code {
List<string> gamesUI; // <--- workaround
protected override async Task OnInitializedAsync()
{
gamesUI = new List<string>();
await foreach(var game in GService.GetgamesAsync() )
{
gamesUI.Add(game);
this.StateHasChanged();
}
}
}
效果:
产量数据:
private static readonly string[] games = new[] { "Call of Duty", "Legend of Zelda", "Super Mario 64", "Bag man" };
public async IAsyncEnumerable<string> GetgamesAsync()
{
var rng = new Random();
foreach (var game in games)
{
await Task.Delay(1000);
yield return game;
}
}