Blazor Workshop项目实战:实现订单数据验证功能

Blazor Workshop项目实战:实现订单数据验证功能

【免费下载链接】blazor-workshop Blazor workshop 【免费下载链接】blazor-workshop 项目地址: https://gitcode.com/gh_mirrors/bl/blazor-workshop

在Web应用开发中,数据验证是确保数据完整性和用户体验的关键环节。Blazor Workshop项目通过一个披萨订购系统,展示了如何在Blazor应用中实现完整的客户端和服务器端数据验证。本文将深入探讨订单数据验证的实现细节,帮助你掌握Blazor验证机制的核心技术。

验证架构概览

Blazor Workshop采用双层验证架构,确保数据的完整性和安全性:

mermaid

核心技术组件

组件作用位置
DataAnnotations定义验证规则共享模型层
EditForm包装表单组件客户端组件
EditContext跟踪编辑状态客户端组件
InputText数据绑定输入控件客户端组件
ValidationMessage显示验证消息客户端组件
DataAnnotationsValidator执行验证逻辑客户端组件
[ApiController]自动验证请求服务器端控制器

数据模型验证规则定义

Address.cs中定义地址模型的验证规则:

using System.ComponentModel.DataAnnotations;

namespace BlazingPizza.Shared;

public class Address
{
    public int Id { get; set; }
    
    [Required, MaxLength(100)]
    public string Name { get; set; } = string.Empty;

    [Required, MaxLength(100)]
    public string Line1 { get; set; } = string.Empty;

    [MaxLength(100)]
    public string Line2 { get; set; } = string.Empty;

    [Required(ErrorMessage = "We need to know which city to deliver to"), MaxLength(50)]
    public string City { get; set; } = string.Empty;

    [Required, MaxLength(20)]
    public string Region { get; set; } = string.Empty;

    [Required, MaxLength(20)]
    public string PostalCode { get; set; } = string.Empty;
}

验证规则详解

属性验证规则错误消息业务意义
Name必填,最大100字符默认消息收货人姓名
Line1必填,最大100字符默认消息地址第一行
Line2最大100字符默认消息地址第二行(可选)
City必填,最大50字符自定义友好消息配送城市
Region必填,最大20字符默认消息地区/省份
PostalCode必填,最大20字符默认消息邮政编码

客户端验证实现

地址编辑器组件

AddressEditor.razor组件负责渲染地址输入表单:

<div class="form-field">
    <label>Name:</label>
    <div>
        <InputText @bind-Value="Address.Name" />
        <ValidationMessage For="@(() => Address.Name)" />
    </div>
</div>

<div class="form-field">
    <label>Line 1:</label>
    <div>
        <InputText @bind-Value="Address.Line1" />
        <ValidationMessage For="@(() => Address.Line1)" />
    </div>
</div>

<!-- 其他字段类似实现 -->

@code {
    [Parameter, EditorRequired] 
    public Address Address { get; set; } = new();
}

结账页面集成验证

Checkout.razor页面整合所有验证组件:

@page "/checkout"
@rendermode InteractiveWebAssembly
@inject OrderState OrderState
@inject IRepository Repository
@inject NavigationManager NavigationManager

<PageTitle>Blazing Pizza - Checkout</PageTitle>

<div class="main">
    <EditForm EditContext="EditContext" OnValidSubmit="PlaceOrder">
        <div class="checkout-cols">
            <div class="checkout-order-details">
                <h4>Review order</h4>
                <OrderReview Order="OrderState.Order" />
            </div>
            
            <div class="checkout-delivery-address">
                <h4>Deliver to...</h4>
                <AddressEditor Address="OrderState.Order.DeliveryAddress" />
            </div>
        </div>

        <button class="checkout-button btn btn-warning" type="submit">
            Place order
        </button>

        <DataAnnotationsValidator />
        <ValidationSummary />
    </EditForm>
</div>

@code {
    public EditContext EditContext { get; set; } = new EditContext(new Order());

    override protected async Task OnAfterRenderAsync(bool first)
    {
        if (first)
        {
            EditContext = new EditContext(OrderState.Order.DeliveryAddress);
            EditContext.SetFieldCssClassProvider(new BootstrapFieldClassProvider());
            StateHasChanged();
        }
    }

    async Task PlaceOrder()
    {
        var newOrderId = await Repository.PlaceOrder(OrderState.Order);
        OrderState.ResetOrder();
        NavigationManager.NavigateTo($"myorders/{newOrderId}");
    }
}

自定义CSS类提供器

BootstrapFieldClassProvider.cs实现字段状态样式:

using Microsoft.AspNetCore.Components.Forms;

namespace BlazingPizza.Client;

public class BootstrapFieldClassProvider : FieldCssClassProvider
{
    public override string GetFieldCssClass(EditContext editContext,
            in FieldIdentifier fieldIdentifier)
    {
        var isValid = editContext.IsValid(fieldIdentifier);
        return isValid ? "is-valid" : "is-invalid";
    }
}

服务器端验证机制

API控制器配置

OrdersController.cs通过[ApiController]属性启用自动验证:

[Route("orders")]
[ApiController]
[Authorize]
public class OrdersController : Controller
{
    private readonly PizzaStoreContext _db;

    public OrdersController(PizzaStoreContext db)
    {
        _db = db;
    }

    [HttpPost]
    public async Task<ActionResult<int>> PlaceOrder(Order order)
    {
        // 如果验证失败,自动返回400 Bad Request
        order.CreatedTime = DateTime.Now;
        order.DeliveryLocation = new LatLong(51.5001, -0.1239);
        order.UserId = PizzaApiExtensions.GetUserId(HttpContext);

        // 处理订单逻辑...
        _db.Orders.Attach(order);
        await _db.SaveChangesAsync();

        return order.OrderId;
    }
}

验证流程详解

客户端验证流程

mermaid

服务器端验证流程

mermaid

高级验证特性

实时验证反馈

Blazor的输入组件提供实时验证反馈:

  1. 即时验证:字段失去焦点时立即验证
  2. 视觉反馈:通过CSS类显示验证状态
  3. 错误消息定位:在对应字段下方显示具体错误

自定义验证逻辑

除了内置的DataAnnotations,还可以:

// 自定义验证属性
public class PizzaNameAttribute : ValidationAttribute
{
    protected override ValidationResult IsValid(object value, ValidationContext context)
    {
        var name = value as string;
        if (name != null && name.Contains("🍕"))
        {
            return new ValidationResult("披萨名称不能包含表情符号");
        }
        return ValidationResult.Success;
    }
}

最佳实践总结

客户端验证最佳实践

  1. 使用合适的输入组件:优先使用InputText等内置组件
  2. 提供即时反馈:实时显示验证状态和消息
  3. 自定义错误消息:使用友好的用户语言
  4. 样式一致性:通过CSS类提供器统一验证样式

服务器端验证最佳实践

  1. 始终验证:不要信任客户端提交的数据
  2. 使用标准机制:利用[ApiController]的自动验证
  3. 业务规则验证:在保存前验证业务逻辑一致性
  4. 错误处理:提供清晰的错误响应

安全考虑

  1. 双重验证:客户端验证改善体验,服务器端验证确保安全
  2. 防篡改:服务器端验证防止恶意请求绕过客户端验证
  3. 数据完整性:确保数据库存储的数据符合业务规则

实战技巧

处理表单提交状态

防止重复提交的增强实现:

@code {
    private bool isSubmitting = false;
    
    async Task PlaceOrder()
    {
        if (isSubmitting) return;
        
        isSubmitting = true;
        try
        {
            var newOrderId = await Repository.PlaceOrder(OrderState.Order);
            OrderState.ResetOrder();
            NavigationManager.NavigateTo($"myorders/{newOrderId}");
        }
        finally
        {
            isSubmitting = false;
            StateHasChanged();
        }
    }
}

条件按钮样式

<button class="checkout-button btn @(isSubmitting ? "btn-secondary" : "btn-warning")" 
        type="submit" disabled="@isSubmitting">
    @(isSubmitting ? "处理中..." : "Place order")
</button>

总结

Blazor Workshop的订单数据验证功能展示了现代Web应用验证的最佳实践。通过结合客户端即时反馈和服务器端强制验证,既提供了优秀的用户体验,又确保了数据的安全性和完整性。

关键要点:

  • 分层验证:客户端改善体验,服务器端确保安全
  • 标准组件:充分利用Blazor内置的表单和验证组件
  • 实时反馈:通过EditContext实现动态验证状态管理
  • 一致性:保持客户端和服务器端验证规则的一致性

掌握这些验证技术,你就能构建出既用户友好又安全可靠的Blazor应用程序。

【免费下载链接】blazor-workshop Blazor workshop 【免费下载链接】blazor-workshop 项目地址: https://gitcode.com/gh_mirrors/bl/blazor-workshop

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值