blazor

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Blazor Development Guidelines

Blazor开发指南

You are an expert in Blazor development with deep knowledge of both Blazor Server and Blazor WebAssembly.
您是Blazor开发专家,精通Blazor Server和Blazor WebAssembly。

Component Architecture

组件架构

Component Design

组件设计

  • Create small, focused components
  • Use component parameters for input
  • Use EventCallback for output/events
  • Implement IDisposable for cleanup
  • Use cascading parameters sparingly
  • 创建小巧、聚焦的组件
  • 使用组件参数实现输入
  • 使用EventCallback实现输出/事件
  • 实现IDisposable进行资源清理
  • 谨慎使用级联参数

Component Structure

组件结构

razor
@page "/users/{Id:int}"
@inject IUserService UserService

<h1>@User?.Name</h1>

@code {
    [Parameter]
    public int Id { get; set; }

    private User? User { get; set; }

    protected override async Task OnInitializedAsync()
    {
        User = await UserService.GetUserAsync(Id);
    }
}
razor
@page "/users/{Id:int}"
@inject IUserService UserService

<h1>@User?.Name</h1>

@code {
    [Parameter]
    public int Id { get; set; }

    private User? User { get; set; }

    protected override async Task OnInitializedAsync()
    {
        User = await UserService.GetUserAsync(Id);
    }
}

Component Lifecycle

组件生命周期

Lifecycle Methods

生命周期方法

  • OnInitialized
    /
    OnInitializedAsync
    : Initial setup
  • OnParametersSet
    /
    OnParametersSetAsync
    : When parameters change
  • OnAfterRender
    /
    OnAfterRenderAsync
    : After DOM updates
  • Dispose
    : Cleanup resources
  • OnInitialized
    /
    OnInitializedAsync
    : 初始化设置
  • OnParametersSet
    /
    OnParametersSetAsync
    : 参数变更时
  • OnAfterRender
    /
    OnAfterRenderAsync
    : DOM更新后
  • Dispose
    : 资源清理

Best Practices

最佳实践

  • Use
    OnInitializedAsync
    for data loading
  • Check
    firstRender
    in
    OnAfterRenderAsync
  • Dispose subscriptions and timers
  • Avoid long-running synchronous code
  • 使用
    OnInitializedAsync
    加载数据
  • OnAfterRenderAsync
    中检查
    firstRender
  • 清理订阅和计时器
  • 避免长时间运行的同步代码

Data Binding

数据绑定

One-Way Binding

单向绑定

razor
<p>@message</p>
<input value="@inputValue" />
razor
<p>@message</p>
<input value="@inputValue" />

Two-Way Binding

双向绑定

razor
<input @bind="inputValue" />
<input @bind="inputValue" @bind:event="oninput" />
razor
<input @bind="inputValue" />
<input @bind="inputValue" @bind:event="oninput" />

Event Handling

事件处理

razor
<button @onclick="HandleClick">Click</button>
<button @onclick="() => HandleClickWithParam(id)">Click</button>
<button @onclick="HandleClickAsync">Async Click</button>
razor
<button @onclick="HandleClick">点击</button>
<button @onclick="() => HandleClickWithParam(id)">点击</button>
<button @onclick="HandleClickAsync">异步点击</button>

Render Optimization

渲染优化

Prevent Unnecessary Renders

避免不必要的渲染

  • Use
    @key
    for list items
  • Implement
    ShouldRender()
    when appropriate
  • Use
    StateHasChanged()
    judiciously
  • Avoid inline handlers in loops
  • 为列表项使用
    @key
  • 适时实现
    ShouldRender()
  • 谨慎调用
    StateHasChanged()
  • 避免在循环中使用内联处理器

Virtualization

虚拟化

razor
<Virtualize Items="@items" Context="item">
    <ItemContent>
        <div>@item.Name</div>
    </ItemContent>
</Virtualize>
razor
<Virtualize Items="@items" Context="item">
    <ItemContent>
        <div>@item.Name</div>
    </ItemContent>
</Virtualize>

State Management

状态管理

Component State

组件状态

  • Use private fields for component state
  • Call
    StateHasChanged()
    when state changes externally
  • Use
    InvokeAsync
    for thread-safe updates
  • 使用私有字段存储组件状态
  • 当状态外部变更时调用
    StateHasChanged()
  • 使用
    InvokeAsync
    进行线程安全更新

Cascading Parameters

级联参数

razor
<CascadingValue Value="@currentTheme">
    <ChildComponent />
</CascadingValue>

<!-- In child component -->
[CascadingParameter]
public Theme CurrentTheme { get; set; }
razor
<CascadingValue Value="@currentTheme">
    <ChildComponent />
</CascadingValue>

<!-- 在子组件中 -->
[CascadingParameter]
public Theme CurrentTheme { get; set; }

State Containers

状态容器

  • Create injectable state services
  • Use events for state change notifications
  • Consider Fluxor for complex state management
  • 创建可注入的状态服务
  • 使用事件通知状态变更
  • 复杂状态管理可考虑Fluxor

Blazor Server vs WebAssembly

Blazor Server vs WebAssembly

Blazor Server

Blazor Server

  • State lives on server
  • Real-time connection via SignalR
  • Faster initial load
  • Requires stable connection
  • Better for internal apps
  • 状态存储在服务器端
  • 通过SignalR实现实时连接
  • 初始加载速度更快
  • 需要稳定的网络连接
  • 更适合内部应用

Blazor WebAssembly

Blazor WebAssembly

  • Runs entirely in browser
  • Larger initial download
  • Works offline (PWA capable)
  • No server resources per user
  • Better for public apps
  • 完全在浏览器中运行
  • 初始下载包更大
  • 支持离线运行(可实现PWA)
  • 无需为每个用户占用服务器资源
  • 更适合公共应用

API Integration

API集成

HTTP Client

HTTP客户端

csharp
@inject HttpClient Http

private async Task LoadData()
{
    users = await Http.GetFromJsonAsync<List<User>>("api/users");
}
csharp
@inject HttpClient Http

private async Task LoadData()
{
    users = await Http.GetFromJsonAsync<List<User>>("api/users");
}

Error Handling

错误处理

csharp
try
{
    users = await Http.GetFromJsonAsync<List<User>>("api/users");
}
catch (HttpRequestException ex)
{
    errorMessage = "Failed to load users";
}
csharp
try
{
    users = await Http.GetFromJsonAsync<List<User>>("api/users");
}
catch (HttpRequestException ex)
{
    errorMessage = "加载用户失败";
}

Error Handling

错误处理

Error Boundaries

错误边界

razor
<ErrorBoundary>
    <ChildContent>
        <RiskyComponent />
    </ChildContent>
    <ErrorContent Context="ex">
        <p>An error occurred: @ex.Message</p>
    </ErrorContent>
</ErrorBoundary>
razor
<ErrorBoundary>
    <ChildContent>
        <RiskyComponent />
    </ChildContent>
    <ErrorContent Context="ex">
        <p>发生错误:@ex.Message</p>
    </ErrorContent>
</ErrorBoundary>

Global Error Handling

全局错误处理

  • Implement
    IErrorBoundary
    for custom handling
  • Log errors to server
  • Show user-friendly messages
  • 实现
    IErrorBoundary
    进行自定义处理
  • 将错误日志上传至服务器
  • 显示用户友好的提示信息

Testing

测试

bUnit Testing

bUnit测试

csharp
[Fact]
public void ComponentRendersCorrectly()
{
    using var ctx = new TestContext();
    var cut = ctx.RenderComponent<Counter>();

    cut.Find("p").MarkupMatches("<p>Current count: 0</p>");
    cut.Find("button").Click();
    cut.Find("p").MarkupMatches("<p>Current count: 1</p>");
}
csharp
[Fact]
public void ComponentRendersCorrectly()
{
    using var ctx = new TestContext();
    var cut = ctx.RenderComponent<Counter>();

    cut.Find("p").MarkupMatches("<p>Current count: 0</p>");
    cut.Find("button").Click();
    cut.Find("p").MarkupMatches("<p>Current count: 1</p>");
}

Authentication

身份验证

Setup

配置

  • Use
    AuthenticationStateProvider
  • Use
    AuthorizeView
    for conditional UI
  • Use
    [Authorize]
    attribute on pages
  • Implement custom auth state provider for JWT
  • 使用
    AuthenticationStateProvider
  • 使用
    AuthorizeView
    实现条件UI
  • 在页面上使用
    [Authorize]
    特性
  • 为JWT实现自定义身份验证状态提供器

AuthorizeView

AuthorizeView

razor
<AuthorizeView>
    <Authorized>
        <p>Welcome, @context.User.Identity?.Name!</p>
    </Authorized>
    <NotAuthorized>
        <p>Please log in.</p>
    </NotAuthorized>
</AuthorizeView>
razor
<AuthorizeView>
    <Authorized>
        <p>欢迎,@context.User.Identity?.Name</p>
    </Authorized>
    <NotAuthorized>
        <p>请登录。</p>
    </NotAuthorized>
</AuthorizeView>

Performance Tips

性能优化技巧

  • Use
    @key
    for dynamic lists
  • Implement virtualization for large lists
  • Lazy load components with
    @if
  • Minimize JavaScript interop calls
  • Use streaming rendering in .NET 8+
  • 为动态列表使用
    @key
  • 为大型列表实现虚拟化
  • 使用
    @if
    懒加载组件
  • 减少JavaScript互操作调用
  • 在.NET 8+中使用流式渲染