managedcode

dotnet-blazor

1
0
# Install this skill:
npx skills add managedcode/dotnet-skills --skill "dotnet-blazor"

Install specific skill from multi-skill repository

# Description

Build and review Blazor applications across server, WebAssembly, web app, and hybrid scenarios with correct component design, state flow, rendering, and hosting choices.

# SKILL.md


name: dotnet-blazor
version: "1.0.0"
category: "Web"
description: "Build and review Blazor applications across server, WebAssembly, web app, and hybrid scenarios with correct component design, state flow, rendering, and hosting choices."
compatibility: "Requires Blazor project (.NET 6+, preferably .NET 8+ for unified model)."


Blazor

Trigger On

  • building interactive web UIs with C# instead of JavaScript
  • choosing between Server, WebAssembly, or Auto render modes
  • designing component hierarchies and state management
  • handling prerendering and hydration
  • integrating with JavaScript when necessary

Documentation

References

  • patterns.md - Detailed component patterns, state management strategies, and JS interop techniques
  • anti-patterns.md - Common Blazor mistakes and how to avoid them

Render Modes (.NET 8+)

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

Applying Render Modes

@* Per-component *@
@rendermode InteractiveServer

@* Or in App.razor for global *@
<Routes @rendermode="InteractiveAuto" />

InteractiveAuto Architecture

First Request:
  Browser β†’ Server (Interactive Server) β†’ Fast response

Subsequent Requests:
  Browser β†’ WASM (downloaded in background) β†’ No server needed

Workflow

  1. Choose render mode based on requirements:
  2. Need SEO? Start with Static or prerendering
  3. Need real-time? Use InteractiveServer
  4. Need offline? Use InteractiveWebAssembly
  5. Want both? Use InteractiveAuto

  6. Design components for reusability:

  7. Small, focused components
  8. Parameters for customization
  9. Events for communication

  10. Handle state correctly:

  11. Component state lives in component
  12. Shared state via services (DI)
  13. Persist state across prerender with [PersistentState]

  14. Validate in both environments (for Auto mode)

Component Patterns

Basic Component

@* 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++;
}

Parameter and Event Callbacks

@* 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);
    }
}

State Persistence (.NET 8+)

@* 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");
    }
}

Data Access Pattern for Auto Mode

// 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-Patterns to Avoid

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]

Performance Best Practices

  1. Virtualize large lists:
    razor <Virtualize Items="@products" Context="product"> <ProductCard Product="@product" /> </Virtualize>

  2. Use @key for list diffing:
    razor @foreach (var item in items) { <ItemComponent @key="item.Id" Item="@item" /> }

  3. Debounce rapid events:
    ```csharp
    private Timer? _debounceTimer;

private void OnInput(ChangeEventArgs e)
{
debounceTimer?.Dispose();
_debounceTimer = new Timer(
=> InvokeAsync(DoSearch), null, 300, Timeout.Infinite);
}
```

  1. Lazy load assemblies (WASM):
    csharp var assemblies = await LazyAssemblyLoader .LoadAssembliesAsync(["MyHeavyFeature.wasm"]);

JS Interop

Calling JavaScript from C

@inject IJSRuntime JS

await JS.InvokeVoidAsync("alert", "Hello from Blazor!");
var result = await JS.InvokeAsync<string>("prompt", "Enter name:");

Calling C# from JavaScript

[JSInvokable]
public static string GetMessage() => "Hello from C#!";
DotNet.invokeMethodAsync('MyAssembly', 'GetMessage')
    .then(result => console.log(result));

Deliver

  • interactive Blazor components with appropriate render mode
  • efficient state management and data flow
  • proper handling of prerendering scenarios
  • performant list rendering with virtualization

Validate

  • components render correctly in chosen mode
  • state persists correctly across prerender/hydration
  • no unnecessary re-renders (check with browser tools)
  • JS interop works in both Server and WASM
  • error boundaries catch component failures
  • Auto mode works in both environments

# Supported AI Coding Agents

This skill is compatible with the SKILL.md standard and works with all major AI coding agents:

Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.