razor-pages - 您可以在 Razor 页面中使用 IAsyncEnumerable 来逐步显示标记吗?

标签 razor-pages blazor asp.net-core-3.0 c#-8.0 iasyncenumerable

我一直在使用 Blazor 和 C# 8.0 中的 IAsyncEnumerable 功能。是否可以在 Razor Pages 中使用 IAsyncEnumerable 和 wait 来逐步显示数据标记?

示例服务:

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;
   }
}

Razor 页面中的示例:

@await foreach(var game in GameService.GetGames())
{
  <p>@game</p>
}

这会产生错误 CS4033:“await”运算符只能在异步方法中使用。考虑使用“async”修饰符标记此方法并将其返回类型更改为“Task”。

如果这可能的话有什么想法吗?

最佳答案

服务器端 Razor 允许您所描述的内容。 This video描述了 this Github repo 中的代码该示例展示了如何通过修改服务器端 Blazor 模板中的 ForecastService 示例来使用 IAsyncEnumerable。

修改服务本身很容易,并且实际上会产生更清晰的代码:

    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)]
            };
        }
    }

另一方面,Blazor 页面更为复杂。这不仅是循环必须在显示 HTML 之前完成,而且您不能在页面本身中使用 await foreach 因为它不是异步的。您只能在代码块中定义异步方法。

您可以做的是枚举 IAsyncEnumerable 并通知页面在每次更改后刷新自身。

渲染代码本身不需要更改:

    <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>

OnInitializedAsync 需要在收到每个项目后调用 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();            
        }
    }

在问题的示例中,传入的游戏可以存储在列表中,保持渲染代码不变:

@foreach(var game in games)
{
  <p>@game</p>
}

@code {
    List<string> games;

    protected override async Task OnInitializedAsync()
    {
        games =new List<games>(); 
        await foreach(var game in GameService.GetGamesAsync())
        {
            games.Add(game);
            this.StateHasChanged();            
        }
    }
}

关于razor-pages - 您可以在 Razor 页面中使用 IAsyncEnumerable 来逐步显示标记吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57870709/

相关文章:

asp.net-mvc - 在 web.config 文件中全局验证文本框控件的 html 标记输入

asp.net-core - 如何在 aspnetcore razor View 页面 (.cshtml) 中启用#nullable

css - ASP.NET Core razor pages 应用程序左侧带有关闭和打开按钮的导航菜单

blazor - 如何声明 Blazor 组件<TData,TValue>?

c# - 将枚举的每个值绑定(bind)到复选框 Blazor

c# - asp.net core 3 中的 CorsAuthorizationFilterFactory

asp.net-core - 相对页面路径 'About' 只能在执行 Razor 页面时使用。指定一个

asp.net-core - Blazor:如何从子组件中的事件中获取发送者

asp.net-core - 每个请求加载不同的配置

c# - ASP.NET Core 3.0 中 ExpressionHelper 的替代品?