dotnet
免费Primary router skill for broad .NET work. Classify the repo by app model and cross-cutting concern first, then switch to the narrowest matching .NET skill instead of staying at a generic layer.
中文简介正在准备中。当前显示原文说明。
Build and review Blazor applications across server, WebAssembly, web app, and hybrid scenarios with correct component design, state flow, rendering, and hosting choices.
中文简介正在准备中。当前显示原文说明。
查看安装方法安装前可以查看交给 AI 代理的指令内容。
| Mode | Where It Runs | Best For |
|---|---|---|
Static | Server (no interactivity) | SEO pages, marketing content |
InteractiveServer | Server via SignalR | Real-time apps, thin clients |
InteractiveWebAssembly | Browser via WASM | Offline-capable, client-heavy |
InteractiveAuto | Server first, then WASM | Best of both worlds |
@* Per-component *@
@rendermode InteractiveServer
@* Or in App.razor for global *@
<Routes @rendermode="InteractiveAuto" />
First Request:
Browser → Server (Interactive Server) → Fast response
Subsequent Requests:
Browser → WASM (downloaded in background) → No server needed
Choose render mode based on requirements:
Design components for reusability:
Handle state correctly:
[PersistentState]Validate in both environments (for Auto mode)
@* Counter.razor *@
<button @onclick="IncrementCount">
Clicked @count times
</button>
@code {
private int count = 0;
[Parameter]
public int InitialCount { get; set; } = 0;
protected override void OnInitialized()
{
count = InitialCount;
}
private void IncrementCount() => count++;
}
@* Parent.razor *@
<ChildComponent Value="@value" ValueChanged="@OnValueChanged" />
@* ChildComponent.razor *@
@code {
[Parameter] public string Value { get; set; } = "";
[Parameter] public EventCallback<string> ValueChanged { get; set; }
private async Task UpdateValue(string newValue)
{
await ValueChanged.InvokeAsync(newValue);
}
}
@* Prevents double-fetch during prerender + hydration *@
@code {
[PersistentState]
public List<Product> Products { get; set; } = [];
protected override async Task OnInitializedAsync()
{
// Only fetches once, persisted across prerender
Products ??= await Http.GetFromJsonAsync<List<Product>>("api/products");
}
}
// Shared interface
public interface IProductService
{
Task<List<Product>> GetProductsAsync();
}
// Server implementation (direct DB access)
public class ServerProductService : IProductService
{
private readonly AppDbContext _db;
public async Task<List<Product>> GetProductsAsync()
=> await _db.Products.ToListAsync();
}
// Client implementation (HTTP call)
public class ClientProductService : IProductService
{
private readonly HttpClient _http;
public async Task<List<Product>> GetProductsAsync()
=> await _http.GetFromJsonAsync<List<Product>>("api/products");
}
// Registration
// Server: builder.Services.AddScoped<IProductService, ServerProductService>();
// Client: builder.Services.AddScoped<IProductService, ClientProductService>();
| Anti-Pattern | Why It's Bad | Better Approach |
|---|---|---|
| Large components | Hard to maintain, slow renders | Split into smaller components |
| Direct DB access in WASM | No DB in browser | Use HTTP API |
Ignoring ShouldRender | Unnecessary re-renders | Override when needed |
| Sync JS interop in Server | Blocks SignalR circuit | Use IJSRuntime async |
| No error boundaries | One error crashes app | Use <ErrorBoundary> |
| Forgetting prerender state | Double API calls | Use [PersistentState] |
Virtualize large lists:
<Virtualize Items="@products" Context="product">
<ProductCard Product="@product" />
</Virtualize>
Use @key for list diffing:
@foreach (var item in items)
{
<ItemComponent @key="item.Id" Item="@item" />
}
Debounce rapid events:
private Timer? _debounceTimer;
private void OnInput(ChangeEventArgs e)
{
_debounceTimer?.Dispose();
_debounceTimer = new Timer(_ => InvokeAsync(DoSearch), null, 300, Timeout.Infinite);
}
Lazy load assemblies (WASM):
var assemblies = await LazyAssemblyLoader
.LoadAssembliesAsync(["MyHeavyFeature.wasm"]);
@inject IJSRuntime JS
await JS.InvokeVoidAsync("alert", "Hello from Blazor!");
var result = await JS.InvokeAsync<string>("prompt", "Enter name:");
[JSInvokable]
public static string GetMessage() => "Hello from C#!";
DotNet.invokeMethodAsync('MyAssembly', 'GetMessage')
.then(result => console.log(result));
还没有评价。欢迎分享你的使用感受。
无需登录即可发表。欢迎分享使用感受、提问,或说明在哪些环境下无法运行。
还没有评论。来写第一条吧。
Primary router skill for broad .NET work. Classify the repo by app model and cross-cutting concern first, then switch to the narrowest matching .NET skill instead of staying at a generic layer.
中文简介正在准备中。当前显示原文说明。
Use a repo-root `.editorconfig` to configure free .NET analyzer and style rules. Use when a .NET repo needs rule severity, code-style options, section layout, or analyzer ownership made explicit. Nested `.editorconfig` files are allowed when they serve a clear subtree-specific purpose.
中文简介正在准备中。当前显示原文说明。
Build, debug, modernize, or review ASP.NET Core applications with correct hosting, middleware, security, configuration, logging, and deployment patterns on current .NET.
中文简介正在准备中。当前显示原文说明。
Use Biome in .NET repositories that ship Node-based frontend assets and want a fast combined formatter-linter-import organizer for JavaScript, TypeScript, CSS, JSON, GraphQL, or HTML. Use when a repo prefers a modern all-in-one CLI over a larger ESLint plus Prettier style stack.
中文简介正在准备中。当前显示原文说明。
Use the free built-in .NET SDK analyzers and analysis levels with gradual Roslyn warning promotion. Use when a .NET repo needs first-party code analysis, `EnableNETAnalyzers`, `AnalysisLevel`, or warning-as-error policy wired into build and CI.
中文简介正在准备中。当前显示原文说明。
Use the open-source free `CSharpier` formatter for C# and XML. Use when a .NET repo intentionally wants one opinionated formatter instead of a highly configurable `dotnet format`-driven style model.
中文简介正在准备中。当前显示原文说明。