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.37k stars 9.99k forks source link

Blazor forms with @formname set from Razor expressions cannot be submitted #50882

Closed DamianEdwards closed 1 year ago

DamianEdwards commented 1 year ago

Found when updating an app from an rc.2 build to latest rtm build.

Info

SDK version: 8.0.100-rtm.23471.13

Repro

  1. Create a new Blazor Web App
  2. Update the Home.razor to the following:

    @page "/"
    
    <PageTitle>Home</PageTitle>
    
    <h1>Hello, world!</h1>
    
    Welcome to your new app.
    
    @if (items is not null)
    {
        @foreach (var item in items)
        {
            <form method="post" @formname="@($"addtocart-{item.Id}")" @onsubmit="HandleAddToCart">
                <input type="hidden" name="ItemId" value="@item.Id" />
                <input type="hidden" name="ItemName" value="@item.Name" />
                <AntiforgeryToken />
    
                <strong>@item.Name</strong> <button type="submit">Add to cart</button>
            </form>
        }
    }
    else
    {
        <p>Loading...</p>
    }
    
    @if (!string.IsNullOrEmpty(message))
    {
        <p>@message</p>
    }
    
    @code {
        private List<Item>? items;
        private string? message;
    
        [SupplyParameterFromForm]
        public int? ItemId { get; set; }
    
        [SupplyParameterFromForm]
        public string? ItemName { get; set; }
    
        protected override void OnInitialized()
        {
            // Load items
            items = [new(1, "Item 1"), new(2, "Item 2"), new(3, "Item 3")];
        }
    
        private void HandleAddToCart()
        {
            message = $"Added {ItemName} with id {ItemId} to cart";
        }
    
        record Item(int Id, string Name);
    }
  3. Run the app and try to click one of the "Add to cart" buttons

Expected

The form can be submitted successfully and the form handler runs.

Actual

An error message is shown in the browser:

The POST request does not specify which form is being submitted. To fix this, ensure <form> elements have a @formname attribute with any unique value, or pass a FormName parameter if using <EditForm>.
marinasundstrom commented 1 year ago

I was trying to reproduce this one in RC1. Then I saw "RTM" and who posted it 😂 I didn't get that message though. The handler executed, but the parameters are not bound.

So the behavior is supposed to have changed? And there is a bug as well?

I get confused because I'm used to FormEdit and supplying a Model. I apply the [SupplyParameterFromForm] to the field or property containing that model object.

In RC1, in order for the parameters to be bound for plain HTML form elements, you need to supply a name matching the path in the model. Such as ItemName, Item.Id, or Model.Id.

<input type="hidden" name="ItemId" value="@item.Id" />
<input type="hidden" name="ItemName" value="@item.Name" />
DamianEdwards commented 1 year ago

After further investigation I've determined this only repros if the form contains a Razor expression nested in an HTML element, nested within the <form> body. The repro code above has this (the <strong>@item.Name</strong>) so you should be able to see the error with that code.

DamianEdwards commented 1 year ago

@marinasundstrom thanks, I've updated the repro code to include the names on the fields to avoid confusion, although it's not strictly related to reproducing this issue.

mkArtakMSFT commented 1 year ago

Thanks Damian. Closing as a dupe of https://github.com/dotnet/razor/issues/9323