Reputation: 6554
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.
I managed to capture the Chrome console error, for all the good it did.
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
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
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