skills/microservice/controlpanel/response-result/SKILL.md
Use when handling API responses with ResponseResult<T> and Switch pattern in the UI.
npx skillsauth add faysilalshareef/dotnet-ai-kit response-resultInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
ResponseResult<T> encapsulates success or failure from gateway callsSwitch() routes to appropriate handler (success action or failure action)SwitchAsync() for async handlersProblemDetails for structured error informationnamespace {Company}.{Domain}.ControlPanel.Models;
public abstract record ResponseResult<T>
{
public static ResponseResult<T> Success(T data) => new SuccessResult<T>(data);
public static ResponseResult<T> Failure(string detail) =>
new FailedResult<T>(new ProblemDetails { Detail = detail });
public static ResponseResult<T> Failure(ProblemDetails problem) =>
new FailedResult<T>(problem);
}
public sealed record SuccessResult<T>(T Data) : ResponseResult<T>;
public sealed record FailedResult<T>(ProblemDetails Problem) : ResponseResult<T>;
namespace {Company}.{Domain}.ControlPanel.Extensions;
public static class ResponseResultExtensions
{
public static void Switch<T>(
this ResponseResult<T> result,
Action<T> onSuccess,
Action<ProblemDetails> onFailure)
{
switch (result)
{
case SuccessResult<T> success:
onSuccess(success.Data);
break;
case FailedResult<T> failed:
onFailure(failed.Problem);
break;
}
}
public static async Task SwitchAsync<T>(
this ResponseResult<T> result,
Func<T, Task> onSuccess,
Func<ProblemDetails, Task> onFailure)
{
switch (result)
{
case SuccessResult<T> success:
await onSuccess(success.Data);
break;
case FailedResult<T> failed:
await onFailure(failed.Problem);
break;
}
}
public static T? GetDataOrDefault<T>(this ResponseResult<T> result) =>
result is SuccessResult<T> success ? success.Data : default;
public static bool IsSuccess<T>(this ResponseResult<T> result) =>
result is SuccessResult<T>;
}
// Create operation with Snackbar feedback
private async Task CreateOrder()
{
var result = await Gateway.Orders.CreateAsync(request);
result.Switch(
onSuccess: order =>
{
Snackbar.Add("Order created successfully", Severity.Success);
NavigationManager.NavigateTo($"/orders/{order.Id}");
},
onFailure: problem =>
{
Snackbar.Add(problem.Detail ?? "Failed to create order",
Severity.Error);
});
}
// Load data with error handling
private async Task LoadOrderDetails(Guid id)
{
_loading = true;
var result = await Gateway.Orders.GetByIdAsync(id);
result.Switch(
onSuccess: order => _order = order,
onFailure: problem =>
{
Snackbar.Add(problem.Detail ?? "Order not found", Severity.Error);
NavigationManager.NavigateTo("/orders");
});
_loading = false;
StateHasChanged();
}
// Conditional rendering based on result
@if (_order is not null)
{
<OrderDetails Order="_order" />
}
else if (_loading)
{
<MudProgressCircular Indeterminate="true" />
}
private async Task<GridData<OrderSummaryResponse>> LoadServerData(
GridState<OrderSummaryResponse> state)
{
var result = await Gateway.Orders.GetAllAsync(
state.Page + 1, state.PageSize);
return result switch
{
SuccessResult<Paginated<OrderSummaryResponse>> s =>
new GridData<OrderSummaryResponse>(s.Data.Items, s.Data.TotalCount),
_ => new GridData<OrderSummaryResponse>([], 0)
};
}
| Anti-Pattern | Correct Approach | |---|---| | Null checks instead of Switch | Use Switch for explicit success/failure | | Try/catch in UI components | ResponseResult encapsulates errors | | Ignoring failure results | Always handle failure with user feedback | | Generic error messages | Use ProblemDetails.Detail for specific messages |
# Find ResponseResult types
grep -r "ResponseResult<" --include="*.cs" src/ControlPanel/
# Find Switch usage
grep -r "\.Switch(" --include="*.cs" src/ControlPanel/
grep -r "\.Switch(" --include="*.razor" src/ControlPanel/
# Find SuccessResult/FailedResult
grep -r "SuccessResult\|FailedResult" --include="*.cs" src/ControlPanel/
ResponseResult<T> type — do not create a new oneSwitch pattern for all gateway call results_loading flag and MudProgressCirculardata-ai
Use when about to claim work is complete, fixed, passing, or ready — before committing, creating PRs, or moving to the next task. Requires running verification commands and confirming output before making any success claims.
development
Use when encountering any bug, test failure, build error, or unexpected behavior — before proposing fixes or making changes.
development
Use when checkpointing, wrapping up, or handing off an AI-assisted development session.
development
Use when following the Specification-Driven Development lifecycle from plan through ship.