我是 Blazor 新手,从 YouTube 教程开始。 因此,我在 VS 2022(最新版本)和 .NET Runtime 8.0.6 中创建了 Blazor Web App 项目。我在项目中包含了示例代码(天气应用程序),并让它运行而不更改任何示例代码。
当我打开“天气”选项卡时,它应该立即打开天气页面,显示“正在加载...”500 毫秒,然后显示一个包含一些温度的表格。在我的例子中,它会等待 500 毫秒,然后打开天气选项卡并立即显示表格。
这是 blazor 示例文件的代码:
@page "/weather"
@attribute [StreamRendering]
<PageTitle>Weather</PageTitle>
<h1>Weather</h1>
<p>This component demonstrates showing data.</p>
@if (forecasts == null)
{
<p><em>Loading...</em></p>
}
else
{
<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>
}
@code {
private WeatherForecast[]? forecasts;
protected override async Task OnInitializedAsync()
{
// Simulate asynchronous loading to demonstrate streaming rendering
await Task.Delay(2000);
var startDate = DateOnly.FromDateTime(DateTime.Now);
var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" };
forecasts = Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = startDate.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = summaries[Random.Shared.Next(summaries.Length)]
}).ToArray();
}
private class WeatherForecast
{
public DateOnly Date { get; set; }
public int TemperatureC { get; set; }
public string? Summary { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}
}
因此 @attribute [StreamRendering] 不起作用,因为它不会在服务器端异步运行 OnInitializedAsync() 方法。
还有一篇 GitHub 帖子显示了完全相同的问题 https://github.com/dotnet/aspnetcore/issues/52323。 这个与 IIS 压缩问题更相关,不包含适合我的解决方案。就我而言,它也不适用于 http、https 或 IIS。 我使用哪个浏览器也没关系,而且它在我同事的电脑上也无法运行。
在开始使用 Blazor 之前我就已经很沮丧了......
经过我的调查,我发现示例项目中
await Task.Delay(2000);
的用法是错误的。这意味着应用程序将保持2秒,然后数据将显示在页面中。
所以我自定义了
GenerateForecastsAsync
方法来每2秒生成一次数据。这是完整的代码,它对我有用。
@page "/weather"
@attribute [StreamRendering]
<PageTitle>Weather</PageTitle>
<h1>Weather</h1>
<p>This component demonstrates showing data.</p>
@if (forecasts == null)
{
<p><em>Loading...</em></p>
}
else
{
<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>
}
@code {
private List<WeatherForecast> forecasts = [];
protected override async Task OnInitializedAsync()
{
var startDate = DateOnly.FromDateTime(DateTime.Now);
var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" };
// forecasts = Enumerable.Range(1, 5).Select(index => new WeatherForecast
// {
// Date = startDate.AddDays(index),
// TemperatureC = Random.Shared.Next(-20, 55),
// Summary = summaries[Random.Shared.Next(summaries.Length)]
// }).ToArray();
await foreach (var weather in GenerateForecastsAsync(startDate, summaries, 50000))
{
forecasts.Add(weather);
StateHasChanged();
}
}
private async IAsyncEnumerable<WeatherForecast> GenerateForecastsAsync(DateOnly startDate, string[] summaries, int count)
{
for (int i = 0; i < count; i++)
{
yield return new WeatherForecast
{
Date = startDate.AddDays(i),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = summaries[Random.Shared.Next(summaries.Length)]
};
await Task.Delay(2000); // Optional throttling to prevent overwhelming UI
}
}
private class WeatherForecast
{
public DateOnly Date { get; set; }
public int TemperatureC { get; set; }
public string? Summary { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}
}