Skip to content
Development
Skill

/fetch-and-send-data

Call APIs, load data into components, and handle the async lifecycle in Blazor. USE FOR fetching data from a backend, submitting data to an API, displaying loading/error states, registering HttpClient, building service abstractions for Auto/WebAssembly render modes. DO NOT USE

From plugin
dotnet-skills
5.1k96 skills16 agents
Install
$ npx -y skills add dotnet/skills --skill fetch-and-send-data --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/fetch-and-send-data

Context preview

The summary Claude sees to decide when to auto-load this skill.

Call APIs, load data into components, and handle the async lifecycle in Blazor. USE FOR fetching data from a backend, submitting data to an API, displaying loading/error states, registering HttpClient, building service abstractions for Auto/WebAssembly render modes. DO NOT USE

SKILL.md

fetch-and-send-data.SKILL.md
license: MIT
name: fetch-and-send-data
description: Call APIs, load data into components, and handle the async lifecycle in Blazor. USE FOR fetching data from a backend, submitting data to an API, displaying loading/error states, registering HttpClient, building service abstractions for Auto/WebAssembly render modes. DO NOT USE for form validation (see collect-user-input), prerendering persistence (see support-prerendering), or project scaffolding (see create-blazor-project).

Fetch and Send Data

Step 1 — Read AGENTS.md

Check **Interactivity Mode** and **Scope**:

| Mode | Data access | |------|-------------| | None (Static SSR) | Server-side: inject services/`DbContext`. Use `[StreamRendering]` for loading UX. | | Server | Server-side: inject services/`DbContext`. Guard prerender with `??=` + `[PersistentState]`. | | WebAssembly | Browser-side: `HttpClient` only. No direct server access. | | Auto | Both server and browser. Always go through an API. |

Step 2 — Register HttpClient

Only needed when calling external APIs from Server, or always for WebAssembly/Auto. Server components accessing their own database should inject `DbContext` or a service directly.

// Named client — requires Microsoft.Extensions.Http NuGet
builder.Services.AddHttpClient("CatalogAPI", client =>
{
    client.BaseAddress = new Uri("https://api.example.com/");
});

// Typed client
builder.Services.AddHttpClient<CatalogClient>(client =>
    client.BaseAddress = new Uri("https://api.example.com/"));

For WebAssembly/Auto with prerendering, register in **both** server and `.Client` `Program.cs`.

Step 3 — Fetch Data

Simple load

@page "/products"
@inject CatalogClient Catalog

@if (products is null)
{
    <p>Loading…</p>
}
else
{
    @foreach (var p in products)
    {
        <p>@p.Name — @p.Price.ToString("C")</p>
    }
}

@code {
    private Product[]? products;

    protected override async Task OnInitializedAsync()
    {
        products = await Catalog.GetProductsAsync();
    }
}

No error handling needed in the simplest case — wrap the component usage in `<ErrorBoundary>` at the parent/layout level to catch unhandled exceptions.

Static SSR — StreamRendering

Without `[StreamRendering]`, the user sees nothing until `OnInitializedAsync` completes:

@attribute [StreamRendering]

Only affects Static SSR. No effect on interactive components.

Prerendering guard

Prerendering calls `OnInitializedAsync` twice. Skip the duplicate:

[PersistentState] private Product[]? products;

protected override async Task OnInitializedAsync()
{
    products ??= await Catalog.GetProductsAsync();
}

See the `support-prerendering` skill for details.

Step 4 — Handle Errors

Use `<ErrorBoundary>` as the default error strategy. It provides a consistent error experience across all components without any per-component catch logic. Wrap component usage at the layout or parent level:

<ErrorBoundary>
    <ChildContent>
        <ProductList />
    </ChildContent>
    <ErrorContent>
        <div class="alert alert-danger">Something went wrong. Please refresh.</div>
    </ErrorContent>
</ErrorBoundary>

Non-cancellation exceptions (`HttpRequestException`, etc.) propagate to `ErrorBoundary` automatically — no catch blocks needed in the component.

Cancellation is special

`ComponentBase` silently swallows **all** `OperationCanceledException` — both self-initiated (disposal, parameter change) and external (HttpClient timeout). `ErrorBoundary` never sees them. This means:

  • Self-cancellation → silently ignored. Correct behavior, no action needed.
  • External cancellation (timeout) → also silently swallowed. Component gets stuck in loading state. Usually acceptable — timeouts are rare.

When to add in-component error handling

Only add catch blocks when the component needs behavior `ErrorBoundary` can't provide — typically **retries** or **timeout-specific messages**. Even then, only catch what you need:

// Catch only external cancellation (timeouts) — everything else flows to ErrorBoundary
catch (OperationCanceledException ex) when (!cancellationToken.IsCancellationRequested)
{
    Logger.LogWarning(ex, "Request timed out for category {CategoryId}", CategoryId);
    error = "The request timed out. Please try again.";
}

If the component also needs to handle general errors with a retry button instead of letting `ErrorBoundary` take over:

catch (OperationCanceledException ex) when (!cancellationToken.IsCancellationRequested)
{
    Logger.LogWarning(ex, "Request timed out for category {CategoryId}", CategoryId);
    error = "The request timed out. Please try again.";
}
catch (Exception ex)
{
    Logger.LogError(ex, "Failed to load products for category {CategoryId}", CategoryId);
    error = "Unable to load products. Please try again.";
}

Rules

  • **Never display `exception.Message`** — it may contain PII, connection strings, or internal details. Use hardcoded user-friendly messages.
  • **Always log through `ILogger`** — the real exception goes to the logging pipeline.
  • **Services must accept `CancellationToken`** — pass it to every async call so work stops when the component cancels.

Step 5 — Parameter-Driven Reloading

When data depends on a route or query parameter that changes (e.g., navigating between `/products/1` and `/products/2`), use `OnParametersSetAsync` with a guard to skip reloads for parameters that don't affect data.

Pattern: cancel-and-reload with stale data overlay

@page "/products/{CategoryId:int}"
@implements IAsyncDisposable
@inject ProductService ProductService
@inject ILogger<Products> Logger

@if (error is not null)
{
    <div class="alert alert-danger">
        <p>@error</p>
        <button @onclick="LoadAsync">Retry</button>
    </div>
}
else if (products is null)
{
    <p>Loading…</p>
}
else
{
    @if (isLoading)
    {
        <p><em>Refreshing…</em></p>
    }
Read more
Ships withdotnet-skills

This repository contains the .NET team's curated set of core skills and custom agents for coding agents. For information about the Agent Skills standard, see agentskills.io. 📊 Dashboard - Accuracy and efficiency scoring trends for contained plugins (

Get the whole plugin

Other skills on dotnet-skills.