dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.2k stars 9.94k forks source link

Blazor binding wrong value in for loop #22302

Closed water1st closed 4 years ago

water1st commented 4 years ago

Describe the bug

Using variables of for loop to bind a value in for loop body, such as i, will bind all binding values to the values of termination conditions of for loop (step count +1)

To Reproduce

step1:create the webassembly blazor default demo step2:modify the FetchData.razor just like this

@using TEST.DTO
@using System.Net.Http
@page "/fetchdata"
@inject IHttpClientFactory clientFactory

<h1>Weather forecast</h1>

<p>This component demonstrates fetching data from the server.</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>
                <th>Operation</th>
            </tr>
        </thead>
        <tbody>
            @for (int i = 0; i < forecasts.Count; i++)
            {
                var forecast = forecasts[i];
                <tr>
                    <td>@forecast.Date.ToShortDateString()</td>
                    <td>@forecast.TemperatureC</td>
                    <td>@forecast.TemperatureF</td>
                    <td>@forecast.Summary</td>
                    <td><button @onclick="@(e => forecasts.RemoveAt(i))">Remove</button></td>
                </tr>
            }
        </tbody>
    </table>
}

@code {
    private IList<WeatherForecast> forecasts;

    protected override async Task OnInitializedAsync()
    {
        var httpClient = clientFactory.CreateClient("Test");
        forecasts = await httpClient.GetFromJsonAsync<List<WeatherForecast>>("weatherforecast");
    }
}

step3: register HttpClientFactory to ServiceCollection setp4: run server step5: run blazor and click the remove button

Further technical details

If I define a variable "index" and assign the value of "i" to "index" in the for loop body, binding "index" it's work good

        <tbody>
            @for (int i = 0; i < forecasts.Count; i++)
            {
                var index = i;
                var forecast = forecasts[index];
                <tr>
                    <td>@forecast.Date.ToShortDateString()</td>
                    <td>@forecast.TemperatureC</td>
                    <td>@forecast.TemperatureF</td>
                    <td>@forecast.Summary</td>
                    <td><button @onclick="@(e => forecasts.RemoveAt(index))">Remove</button></td>
                </tr>
            }
        </tbody>

运行时环境: OS Name: Windows OS Version: 10.0.18363 OS Platform: Windows RID: win10-x64 Base Path: C:\Program Files\dotnet\sdk\3.1.300\

Host (useful for support): Version: 3.1.4 Commit: 0c2e69caa6

.NET Core SDKs installed: 2.1.701 [C:\Program Files\dotnet\sdk] 2.1.801 [C:\Program Files\dotnet\sdk] 2.1.802 [C:\Program Files\dotnet\sdk] 2.2.205 [C:\Program Files\dotnet\sdk] 2.2.301 [C:\Program Files\dotnet\sdk] 3.0.100 [C:\Program Files\dotnet\sdk] 3.1.102 [C:\Program Files\dotnet\sdk] 3.1.300 [C:\Program Files\dotnet\sdk]

.NET Core runtimes installed: Microsoft.AspNetCore.All 2.1.12 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All] Microsoft.AspNetCore.All 2.1.13 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All] Microsoft.AspNetCore.All 2.1.18 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All] Microsoft.AspNetCore.All 2.2.6 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All] Microsoft.AspNetCore.App 2.1.12 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 2.1.13 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 2.1.18 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 2.2.6 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 3.0.0 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 3.1.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 3.1.4 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.NETCore.App 2.1.12 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 2.1.13 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 2.1.18 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 2.2.6 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 3.0.0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 3.1.2 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 3.1.4 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.WindowsDesktop.App 3.0.0 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App] Microsoft.WindowsDesktop.App 3.1.2 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App] Microsoft.WindowsDesktop.App 3.1.4 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]


- The IDE: VS 2019 16.6.0
javiercn commented 4 years ago

@water1st thanks for contacting us.

This is a known limitation on the Razor compiler. When using the i variable inside the for loop, the code in the event handler closes over the loop variable which is what is causing the issue.

There are a couple of things you can do to avoid this: