Phil Murray
Phil Murray

Reputation: 6554

Blazer EditForm submit does not fire OnValidSubmit & OnInvalidSubmit methods

I am just messing around with my first Blazer server application and have hit an issue when submitting a EditForm. The validation works on the two textboxes that are bound to properties with Required annontations but when I submit the form none of the form methods are invoked and Chrome just reports an error. Any idea what the issue is?

Page

@page "/"
@inject NavigationManager NavigationManager

@using MyModels

<div class="backgroupContainer">
    <EditForm Model="@authModel" OnValidSubmit="HandleValidSubmit" OnInvalidSubmit="HandleInValidSubmit">
        <DataAnnotationsValidator />

        <div id="login">
            <img id="login-image" src="images/img-01.png" alt="Login" />
            <div class="container">
                <div id="login-row" class="row justify-content-center align-items-center">
                    <div id="login-column" class="col-md-6">
                        <div id="login-box" class="col-md-12">
                            <form id="login-form" class="form" action="" method="post">
                                <h3 class="text-center text-info">Login</h3>
                                <div class="form-group">
                                    <label for="username" class="text-info">Username:</label><br>
                                    <InputText id="username" class="form-control" placeholder="Username" @bind-Value="authModel.Username" />
                                    <ValidationMessage For="@(() => authModel.Username)" />
                                </div>
                                <div class="form-group">
                                    <label for="password" class="text-info">Password:</label><br>
                                    <InputText id="password" class="form-control" type="password" placeholder="Password" @bind-Value="authModel.Password" />
                                    <ValidationMessage For="@(() => authModel.Password)" />
                                </div>
                                <div class="form-group">
                                    <button type="submit">Login</button>*
                                </div>
                            </form>
                        </div>
                    </div>
                </div>
            </div>
        </div>

    </EditForm>
</div>

@code {

    private AuthenticationModel authModel = new AuthenticationModel();

    private void HandleLogin()
    {
        System.Diagnostics.Debugger.Break();
        NavigationManager.NavigateTo("counter");
    }

    private void HandleValidSubmit()
    {
        System.Diagnostics.Debugger.Break();
        NavigationManager.NavigateTo("fetchdata");
    }

    private void HandleInValidSubmit()
    {
        System.Diagnostics.Debugger.Break();
        NavigationManager.NavigateTo("error");
    }
}

Display Model

using System.ComponentModel.DataAnnotations;

namespace MyModels
{
    public class AuthenticationModel
    {
        [Required]
        public string Username { get; set; }

        [Required]
        public string Password { get; set; }
    }
}

Chrome

I can see that the Chrome console Dev tools throws an exception but it'g gone way before I can capture it.

enter image description here

I managed to capture the Chrome console error, for all the good it did.

enter image description here

The Visual Studio Output windows displays

Loaded '/usr/share/dotnet/shared/Microsoft.NETCore.App/3.1.5/System.Security.Principal.Windows.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.

And here are the logs from the Docker container

warn: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[60]
      Storing keys in a directory '/root/.aspnet/DataProtection-Keys' that may not be persisted outside of the container. Protected data will be unavailable when container is destroyed. warn: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[35]
      No XML encryptor configured. Key {0405d1c3-4428-4e59-add8-4b1e48db282b} may be persisted to storage in unencrypted form. info: Microsoft.Hosting.Lifetime[0]
      Now listening on: https://[::]:443 info: Microsoft.Hosting.Lifetime[0]
      Now listening on: http://[::]:80 info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down. info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development info: Microsoft.Hosting.Lifetime[0]
      Content root path: /app warn: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[60]
      Storing keys in a directory '/root/.aspnet/DataProtection-Keys' that may not be persisted outside of the container. Protected data will be unavailable when container is destroyed. info: Microsoft.Hosting.Lifetime[0]
      Now listening on: https://[::]:443 info: Microsoft.Hosting.Lifetime[0]
      Now listening on: http://[::]:80 info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down. info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development info: Microsoft.Hosting.Lifetime[0]
      Content root path: /app warn: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[60]
      Storing keys in a directory '/root/.aspnet/DataProtection-Keys' that may not be persisted outside of the container. Protected data will be unavailable when container is destroyed. info: Microsoft.Hosting.Lifetime[0]
      Now listening on: https://[::]:443 info: Microsoft.Hosting.Lifetime[0]
      Now listening on: http://[::]:80 info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down. info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development info: Microsoft.Hosting.Lifetime[0]
      Content root path: /app warn: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[60]
      Storing keys in a directory '/root/.aspnet/DataProtection-Keys' that may not be persisted outside of the container. Protected data will be unavailable when container is destroyed. info: Microsoft.Hosting.Lifetime[0]
      Now listening on: https://[::]:443 info: Microsoft.Hosting.Lifetime[0]
      Now listening on: http://[::]:80 info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down. info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development info: Microsoft.Hosting.Lifetime[0]
      Content root path: /app warn: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[60]
      Storing keys in a directory '/root/.aspnet/DataProtection-Keys' that may not be persisted outside of the container. Protected data will be unavailable when container is destroyed. info: Microsoft.Hosting.Lifetime[0]
      Now listening on: https://[::]:443 info: Microsoft.Hosting.Lifetime[0]
      Now listening on: http://[::]:80 info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down. info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development info: Microsoft.Hosting.Lifetime[0]
      Content root path: /app warn: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[60]
      Storing keys in a directory '/root/.aspnet/DataProtection-Keys' that may not be persisted outside of the container. Protected data will be unavailable when container is destroyed. info: Microsoft.Hosting.Lifetime[0]
      Now listening on: https://[::]:443 info: Microsoft.Hosting.Lifetime[0]
      Now listening on: http://[::]:80 info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down. info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development info: Microsoft.Hosting.Lifetime[0]
      Content root path: /app warn: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[60]
      Storing keys in a directory '/root/.aspnet/DataProtection-Keys' that may not be persisted outside of the container. Protected data will be unavailable when container is destroyed. info: Microsoft.Hosting.Lifetime[0]
      Now listening on: https://[::]:443 info: Microsoft.Hosting.Lifetime[0]
      Now listening on: http://[::]:80 info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down. info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development info: Microsoft.Hosting.Lifetime[0]
      Content root path: /app warn: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[60]
      Storing keys in a directory '/root/.aspnet/DataProtection-Keys' that may not be persisted outside of the container. Protected data will be unavailable when container is destroyed. info: Microsoft.Hosting.Lifetime[0]
      Now listening on: https://[::]:443 info: Microsoft.Hosting.Lifetime[0]
      Now listening on: http://[::]:80 info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down. info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development info: Microsoft.Hosting.Lifetime[0]
      Content root path: /app warn: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[60]
      Storing keys in a directory '/root/.aspnet/DataProtection-Keys' that may not be persisted outside of the container. Protected data will be unavailable when container is destroyed. info: Microsoft.Hosting.Lifetime[0]
      Now listening on: https://[::]:443 info: Microsoft.Hosting.Lifetime[0]
      Now listening on: http://[::]:80 info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down. info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development info: Microsoft.Hosting.Lifetime[0]
      Content root path: /app warn: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[60]
      Storing keys in a directory '/root/.aspnet/DataProtection-Keys' that may not be persisted outside of the container. Protected data will be unavailable when container is destroyed. info: Microsoft.Hosting.Lifetime[0]
      Now listening on: https://[::]:443 info: Microsoft.Hosting.Lifetime[0]
      Now listening on: http://[::]:80 info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down. info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development info: Microsoft.Hosting.Lifetime[0]
      Content root path: /app

Enabling all exceptions and turning off "Just My Code"

Enabling all exception types didn't make any difference but turning off Just My Code debugging gave me the below exceptions

enter image description here

enter image description here

enter image description here

Antiforgery Tokens

Following reading this GitHub issue I changed the below code in the ConfigureServices method of the Startup.cs. It no longer bombs out to the 400 Chrome page but still does not fire the OnValidSubmit or OnInvalidSubmit methods in the page.

    //services.AddRazorPages()

    services.AddRazorPages(o =>
    {
        o.Conventions.ConfigureFilter(new Microsoft.AspNetCore.Mvc.IgnoreAntiforgeryTokenAttribute());
    });

Last edit for the evening

If followed the Forms Validation example from the Blazor Univercity article and it fired the OnValid and OnInalid methods so it must be an issue in my original markup. At the moment I have no idea what.

Working code:

<EditForm Model=@person OnValidSubmit="HandleValidSubmit" OnInvalidSubmit="HandleInValidSubmit">
    <DataAnnotationsValidator />
    <ValidationSummary />
    <div class="form-group">
        <label for="Name">Name</label>
        <InputText @bind-Value=person.Name class="form-control" id="Name" />
    </div>
    <div class="form-group">
        <label for="Age">Age</label>
        <InputNumber @bind-Value=person.Age class="form-control" id="Age" />
    </div>
    <input type="submit" class="btn btn-primary" value="Save" />
</EditForm>

@code {
        Person person = new Person();

        public class Person
        {
            [System.ComponentModel.DataAnnotations.Required]
            public string Name { get; set; }
            [System.ComponentModel.DataAnnotations.Range(18, 80, ErrorMessage = "Age must be between 18 and 80.")]
            public int Age { get; set; }
        }

        private void HandleValidSubmit()
        {
            System.Diagnostics.Debugger.Break();
            NavigationManager.NavigateTo("fetchdata");
        }

        private void HandleInValidSubmit()
        {
            System.Diagnostics.Debugger.Break();
            NavigationManager.NavigateTo("error");
        }
    }

REPO:

https://github.com/PhilipAnthonyMurray/Blazor

Upvotes: 4

Views: 7639

Answers (1)

Peter Morris
Peter Morris

Reputation: 23224

The problem is that you have a <form> in your markup. You don't need that because <EditForm> creates one for you and hooks into the form events.

At the moment, when you submit the form the app re-navigates to the current page, which is why it goes through the OnInitializedAsync method.

As soon as you remove the form, it works.

Upvotes: 7

Related Questions