从邮件打开页面时,OnAfterRenderAsync不会被触发吗?

编程语言 2026-07-10

我有一个服务端应用程序,其中一个功能是用户可以请求重置密码。基本的工作流程是:他们提供用户名,然后会收到一封邮件,里面包含一个指向一个特殊的ResetPassword组件的链接,该链接的URL中也包含一个令牌(作为组件的参数传递)。

在我的OnAfterRenderAsync方法中,在第一次渲染时,我写了一些逻辑来验证令牌,然后确定“重置”按钮是实际处于启用状态还是禁用状态,显示的消息也会根据验证结果而改变。

但是我注意到,通过邮件中的链接进入页面时,页面上的表单模型已被预设,但显示的消息缺失,令牌尚未被验证。点击“重置密码”按钮也没有任何反应。

我应该提到,我确实在 @rendermode InteractiveServer 的Routes.razor中,并且到目前为止应用的其他部分也没有问题。我也在使用net10。

也许我对Blazor的工作方式还存在一些误解。下面是相关代码。

@page "/resetpassword/{tokenID}/"
@attribute [AllowAnonymous]
@using TestApp.Test.Repository.iRepository
@using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage
@using Microsoft.Data.SqlClient
@using System.Data
@using Microsoft.VisualBasic
@using System.ComponentModel.DataAnnotations
@inject ProtectedSessionStorage protectedSessionStore
@inject NotificationService NotificationService
@inject NavigationManager navManager
@inject IUsersRepository _usersRepository

<MainHeader Header="Reset Password"></MainHeader>
<div style="text-align:center;">
    <RadzenText @bind-Value="displayMessage" TextStyle="TextStyle.H5"></RadzenText>
</div>
<br />
<div style="padding-bottom:10px;">
    <div class="col-sm-5 mx-auto">
        <EditForm Model="resetPassword" OnValidSubmit="ResetPassword" FormName="@resetForm">
            <DataAnnotationsValidator></DataAnnotationsValidator>
            <div class="mb-3">
                <label>Username</label><br>
                <InputText @bind-Value="resetPassword.Username" class="form-control"></InputText>
                <ValidationMessage For="() => resetPassword.Username"></ValidationMessage>
            </div>
            <div class="mb-3">
                <label>Password</label>
                <InputText type="password" @bind-Value="resetPassword.Password" class="form-control"></InputText>
                <ValidationMessage For="() => resetPassword.Password"></ValidationMessage>
            </div>
            <div class="mb-3">
                <label>Re-Enter Password</label>
                <InputText type="password" @bind-Value="resetPassword.ReEnterPassword" class="form-control"></InputText>
                <ValidationMessage For="() => resetPassword.ReEnterPassword"></ValidationMessage>
            </div>
            <div style="text-align:center;">
                <RadzenButton type="submit" Text="Reset Password" Disabled="@validToken" Size="ButtonSize.Medium" ButtonStyle="ButtonStyle.Primary" />
            </div>
        </EditForm>
    </div>
</div>

@code {
    [Parameter]
    public string? tokenID { get; set; }

    private string displayMessage { get; set; } = string.Empty;
    private bool validToken { get; set; } = false;
    private const string resetForm = "reset-password-form";
    [SupplyParameterFromForm(FormName = resetForm)]
    private ResetPasswordModel resetPassword { get; set; } = new();

    class ResetPasswordModel
    {
        [Required]
        public string Username { get; set; } = "";

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

        [Required(ErrorMessage = "The Password field must be re-entered.")]
        [Compare(nameof(Password), ErrorMessage = "Password fields do not match.")]
        public string ReEnterPassword { get; set; } = "";
    }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            if (tokenID != null && tokenID != "")
            {
                var valid = await ValidateToken();
                if (valid)
                {
                    validToken = !valid;
                    displayMessage = "Please enter your username, followed by your new password twice.";
                }
                else
                {
                    validToken = valid;
                    displayMessage = "The time limit for your reset token has expired. Unable to reset password.";
                }
            }

            StateHasChanged();
        }
    }

    private async Task<bool> ValidateToken()
    {
        //Logic for validating token.
    }

解决方案

在理论上如果你是从 ComponentBase 继承的,理论上是不可能的。但是如果代码在渲染器到达 OnAfterRenderAsync 之前就“卡住”了,那么它看起来像是没有运行。

给出两个建议:

  1. 创建一个只有控制台日志的普通测试页,并把它随邮件发送。它会完整运行并执行 OnAfterRenderAsync 吗?我很确定会的。
  2. 在你的页面上,在页面事件 OnInitializedAsync 等处添加控制台日志,以观察它们的运行和完成。
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章