You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 6.0 Blazor Server表单邮箱/手机号后端唯一性验证方案咨询

.NET 6 Blazor Server 实现邮箱唯一性验证的方案

因为.NET 6 不支持向ValidationAttribute注入依赖服务,所以没法直接通过自定义EmailUniqueAttribute实现数据库查询验证,以下是几种可行的替代方案:

方案一:表单提交前手动调用验证服务

这是最直接的方式,在表单通过数据注解验证后,手动调用邮箱唯一性检查服务,根据结果决定是否继续执行注册逻辑。

步骤1:定义邮箱唯一性检查服务

先创建一个负责查询数据库的服务:

public interface IEmailUniquenessChecker
{
    Task<bool> IsEmailUniqueAsync(string email);
}

public class EmailUniquenessChecker : IEmailUniquenessChecker
{
    private readonly AppDbContext _dbContext;

    public EmailUniquenessChecker(AppDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public async Task<bool> IsEmailUniqueAsync(string email)
    {
        // 注意处理邮箱大小写,根据业务需求调整
        return !await _dbContext.Users.AnyAsync(u => u.Email.Equals(email, StringComparison.OrdinalIgnoreCase));
    }
}

记得在Program.cs中注册这个服务:

builder.Services.AddScoped<IEmailUniquenessChecker, EmailUniquenessChecker>();

步骤2:在Blazor组件中实现验证逻辑

在注册表单组件中注入服务,在提交时检查唯一性:

@inject IEmailUniquenessChecker EmailChecker
@inject NavigationManager NavManager

<EditForm Model="@RegisterModel" OnValidSubmit="@HandleValidSubmit">
    <DataAnnotationsValidator />
    <ValidationSummary />

    <div class="mb-3">
        <label class="form-label">邮箱</label>
        <InputText @bind-Value="RegisterModel.Email" class="form-control" />
        <ValidationMessage For="@(() => RegisterModel.Email)" />
    </div>

    <!-- 姓名、电话等其他表单字段 -->

    <button type="submit" class="btn btn-primary">注册</button>
</EditForm>

@code {
    private RegisterViewModel RegisterModel { get; set; } = new();

    private async Task HandleValidSubmit()
    {
        // 检查邮箱唯一性
        var isUnique = await EmailChecker.IsEmailUniqueAsync(RegisterModel.Email);
        if (!isUnique)
        {
            // 添加验证错误并刷新组件显示
            var editContext = new EditContext(RegisterModel);
            editContext.AddModelError(nameof(RegisterModel.Email), "该邮箱已被注册,请更换其他邮箱");
            StateHasChanged();
            return;
        }

        // 唯一性验证通过,执行注册逻辑
        // 示例:将用户信息保存到数据库
        // await _userService.CreateUserAsync(RegisterModel);

        NavManager.NavigateTo("/login");
    }

    public class RegisterViewModel
    {
        [Required(ErrorMessage = "请输入姓名")]
        public string Name { get; set; }

        [Required(ErrorMessage = "请输入邮箱")]
        [EmailAddress(ErrorMessage = "请输入有效的邮箱格式")]
        public string Email { get; set; }

        [Required(ErrorMessage = "请输入电话")]
        [Phone(ErrorMessage = "请输入有效的电话号码")]
        public string Phone { get; set; }
    }
}

方案二:通过EditContext附加实时验证

如果需要在用户输入邮箱后实时验证(比如失去焦点时),可以通过订阅EditContext的验证事件实现:

@inject IEmailUniquenessChecker EmailChecker
@implements IDisposable

<EditForm Model="@RegisterModel" EditContext="@_editContext">
    <DataAnnotationsValidator />
    <ValidationSummary />

    <div class="mb-3">
        <label class="form-label">邮箱</label>
        <InputText @bind-Value="RegisterModel.Email" class="form-control" />
        <ValidationMessage For="@(() => RegisterModel.Email)" />
    </div>

    <!-- 其他表单字段 -->

    <button type="submit" class="btn btn-primary">注册</button>
</EditForm>

@code {
    private RegisterViewModel RegisterModel { get; set; } = new();
    private EditContext _editContext;
    private IDisposable _validationSubscription;

    protected override void OnInitialized()
    {
        _editContext = new EditContext(RegisterModel);
        // 订阅验证请求事件
        _validationSubscription = _editContext.OnValidationRequested += async (sender, args) =>
        {
            var emailField = _editContext.Field(nameof(RegisterModel.Email));
            var email = RegisterModel.Email;

            if (!string.IsNullOrWhiteSpace(email))
            {
                var isUnique = await EmailChecker.IsEmailUniqueAsync(email);
                if (!isUnique)
                {
                    _editContext.AddModelError(emailField, "该邮箱已被注册");
                }
                else
                {
                    // 清除之前的错误(如果有)
                    _editContext.MarkFieldAsValid(emailField);
                }
            }
            else
            {
                // 邮箱为空时,保留数据注解的必填验证,不处理唯一性
                _editContext.MarkFieldAsValid(emailField);
            }
        };
    }

    public void Dispose()
    {
        // 释放订阅,避免内存泄漏
        _validationSubscription?.Dispose();
    }

    // RegisterViewModel 定义同方案一
}

方案三:结合自定义验证组件

如果希望封装验证逻辑,可以创建一个独立的验证组件,复用在多个表单中:

@inject IEmailUniquenessChecker EmailChecker
@implements IDisposable

[Parameter] public EditContext EditContext { get; set; }
[Parameter] public Expression<Func<string>> For { get; set; }

@code {
    private FieldIdentifier _fieldIdentifier;
    private IDisposable _fieldSubscription;

    protected override void OnInitialized()
    {
        _fieldIdentifier = FieldIdentifier.Create(For);
        // 订阅字段值变更事件,实时验证
        _fieldSubscription = EditContext.OnFieldChanged += async (sender, args) =>
        {
            if (args.FieldIdentifier == _fieldIdentifier)
            {
                await ValidateEmailAsync();
            }
        };
    }

    private async Task ValidateEmailAsync()
    {
        var email = EditContext.Model.GetType().GetProperty(_fieldIdentifier.FieldName)?.GetValue(EditContext.Model) as string;
        if (!string.IsNullOrWhiteSpace(email))
        {
            var isUnique = await EmailChecker.IsEmailUniqueAsync(email);
            if (!isUnique)
            {
                EditContext.AddModelError(_fieldIdentifier, "该邮箱已被注册");
            }
            else
            {
                EditContext.MarkFieldAsValid(_fieldIdentifier);
            }
        }
        else
        {
            EditContext.MarkFieldAsValid(_fieldIdentifier);
        }
    }

    public void Dispose()
    {
        _fieldSubscription?.Dispose();
    }
}

然后在注册表单中使用这个组件:

<EditForm Model="@RegisterModel">
    <DataAnnotationsValidator />
    <ValidationSummary />

    <div class="mb-3">
        <label class="form-label">邮箱</label>
        <InputText @bind-Value="RegisterModel.Email" class="form-control" />
        <ValidationMessage For="@(() => RegisterModel.Email)" />
        <EmailUniqueValidator For="@(() => RegisterModel.Email)" />
    </div>

    <!-- 其他字段 -->
</EditForm>

内容的提问来源于stack exchange,提问作者bacis09

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 08:55:17