一键导入
blazor-patterns
Blazor Server/WASM/Auto render modes, streaming SSR, state management, forms, JS interop, lifecycle, SignalR. Auto-loads for .razor work.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Blazor Server/WASM/Auto render modes, streaming SSR, state management, forms, JS interop, lifecycle, SignalR. Auto-loads for .razor work.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Full-project health audit — spawns 5 specialists (dotnet-reviewer, security-analyzer, testing-reviewer, performance-profiler, deployment-validator) in parallel. Use for onboarding or pre-release.
Analyze project/namespace boundaries, detect circular refs and layering violations via dotnet-depends and solution graph. Use before major refactors or to validate Clean Architecture.
Senior-engineer challenge mode — aggressively question the current approach, hunt for N+1 queries, captive deps, missing auth, sync-over-async, leaks. Use before finalizing significant changes.
Capture a solved problem as institutional knowledge. Writes `.claude/solutions/{category}/{slug}.md` with symptoms, root cause, fix, category, tags. Use after notable fixes.
Generate or update documentation — XML doc comments, README, architecture docs, OpenAPI descriptions. Uses code as source of truth; no hallucinated features.
Extract durable lessons from a just-finished fix — propose CLAUDE.md rule, Iron Law addition, or Solution doc. Use after resolving a surprising/repeatable bug.
| name | blazor-patterns |
| description | Blazor Server/WASM/Auto render modes, streaming SSR, state management, forms, JS interop, lifecycle, SignalR. Auto-loads for .razor work. |
| effort | medium |
Blazor component architecture for .NET 8–11.
StateHasChanged from non-UI thread needs InvokeAsync(...)@key on dynamic listsIDisposable/IAsyncDisposable| Mode | When | Trade-off |
|---|---|---|
| Static SSR (default) | Content pages | No interactivity |
| InteractiveServer | Dashboards, admin, real-time | Circuit overhead |
| InteractiveWebAssembly | Offline-capable, fewer server calls | Slower first load |
| InteractiveAuto | Best of both (SSR prerender → WASM hydrate) | Complex state transfer |
Set per-component or globally in App.razor.
@page "/orders"
@rendermode InteractiveServer
@inject IOrderService OrderService
@implements IAsyncDisposable
<h3>Orders</h3>
@if (isLoading) { <Loading /> }
else
{
<table>
@foreach (var order in orders)
{
<OrderRow @key="order.Id" Order="order" />
}
</table>
}
@code {
private List<OrderDto> orders = [];
private bool isLoading = true;
private readonly CancellationTokenSource _cts = new();
protected override async Task OnInitializedAsync()
{
orders = await OrderService.ListAsync(_cts.Token);
isLoading = false;
}
public async ValueTask DisposeAsync()
{
_cts.Cancel();
_cts.Dispose();
await Task.CompletedTask;
}
}
@code {
protected override void OnInitialized()
{
Notifications.OnOrderUpdated += HandleOrderUpdated;
}
private async void HandleOrderUpdated(object? sender, OrderEventArgs e)
{
// Called from non-UI thread — must InvokeAsync
await InvokeAsync(() =>
{
UpdateLocalOrder(e.Order);
StateHasChanged();
});
}
}
@page "/orders/{Id:long}"
@attribute [StreamRendering(true)]
<h3>Order @Id</h3>
@if (order is null) { <p>Loading...</p> }
else { <OrderDetail Order="order" /> }
@code {
[Parameter] public long Id { get; set; }
private OrderDto? order;
protected override async Task OnInitializedAsync()
{
order = await OrderService.GetAsync(Id); // HTML streams when this resolves
}
}
<EditForm Model="@model" OnValidSubmit="@HandleSubmit">
<FluentValidationValidator />
<InputText @bind-Value="model.Name" />
<ValidationMessage For="@(() => model.Name)" />
<button type="submit" disabled="@isSubmitting">Save</button>
</EditForm>
@inject IJSRuntime JS
@implements IAsyncDisposable
@code {
private IJSObjectReference? module;
private ElementReference gridEl;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
module = await JS.InvokeAsync<IJSObjectReference>("import", "./js/grid.js");
await module.InvokeVoidAsync("init", gridEl);
}
}
public async ValueTask DisposeAsync()
{
if (module is not null)
{
await module.InvokeVoidAsync("destroy");
await module.DisposeAsync();
}
}
}
${CLAUDE_SKILL_DIR}/references/render-modes.md — mode selection + examples${CLAUDE_SKILL_DIR}/references/state-management.md — cascading, DI,
PersistentComponentState${CLAUDE_SKILL_DIR}/references/forms.md — EditForm, validation,
SupplyParameterFromForm${CLAUDE_SKILL_DIR}/references/js-interop.md — module patterns,
disposal, WASM in-process${CLAUDE_SKILL_DIR}/references/lifecycle.md — OnInit/OnParametersSet/
OnAfterRender${CLAUDE_SKILL_DIR}/references/streaming-ssr.md — StreamRendering
attribute.razor.cs — move to services@key on @foreach with reorderable list (Iron Law #20)async void handlers that throw (swallowed — crashes later)