Gateway management class hierarchy for control panel API calls. Covers typed HttpClient wrappers, nested management classes, HTTP extension methods. Trigger: gateway facade, HttpClient, API client, management class.
From dotnet-ai-kitnpx claudepluginhub faysilalshareef/dotnet-ai-kit --plugin dotnet-ai-kitThis skill uses the workspace's default tool permissions.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Compares coding agents like Claude Code and Aider on custom YAML-defined codebase tasks using git worktrees, measuring pass rate, cost, time, and consistency.
HttpClient for calling gateway REST endpoints??= pattern) for management classesHttpExtensions provide consistent serialization and error handlingResponseResult<T> for uniform error handlingnamespace {Company}.{Domain}.ControlPanel.Gateways;
public sealed class OrderGateway(HttpClient http)
{
private OrderManagement? _orders;
private CustomerManagement? _customers;
public OrderManagement Orders => _orders ??= new(http);
public CustomerManagement Customers => _customers ??= new(http);
}
namespace {Company}.{Domain}.ControlPanel.Gateways;
public sealed class OrderManagement(HttpClient http)
{
private const string BaseRoute = "api/v1/orders";
public async Task<ResponseResult<Paginated<OrderSummaryResponse>>> GetAllAsync(
int page, int pageSize, string? search = null)
{
var url = $"{BaseRoute}?page={page}&pageSize={pageSize}";
if (!string.IsNullOrEmpty(search))
url += $"&search={Uri.EscapeDataString(search)}";
return await http.GetAsync<Paginated<OrderSummaryResponse>>(url);
}
public async Task<ResponseResult<OrderDetailResponse>> GetByIdAsync(Guid id)
=> await http.GetAsync<OrderDetailResponse>($"{BaseRoute}/{id}");
public async Task<ResponseResult<OrderResponse>> CreateAsync(
CreateOrderRequest request)
=> await http.PostAsJsonAsync<OrderResponse>(BaseRoute, request);
public async Task<ResponseResult<OrderResponse>> UpdateAsync(
Guid id, UpdateOrderRequest request)
=> await http.PutAsJsonAsync<OrderResponse>($"{BaseRoute}/{id}", request);
public async Task<ResponseResult<bool>> DeleteAsync(Guid id)
=> await http.DeleteAsync<bool>($"{BaseRoute}/{id}");
}
namespace {Company}.{Domain}.ControlPanel.Extensions;
public static class HttpExtensions
{
public static async Task<ResponseResult<T>> GetAsync<T>(
this HttpClient http, string url)
{
try
{
var response = await http.GetAsync(url);
return await HandleResponse<T>(response);
}
catch (Exception ex)
{
return ResponseResult<T>.Failure(ex.Message);
}
}
public static async Task<ResponseResult<T>> PostAsJsonAsync<T>(
this HttpClient http, string url, object content)
{
try
{
var response = await http.PostAsJsonAsync(url, content);
return await HandleResponse<T>(response);
}
catch (Exception ex)
{
return ResponseResult<T>.Failure(ex.Message);
}
}
public static async Task<ResponseResult<T>> PutAsJsonAsync<T>(
this HttpClient http, string url, object content)
{
try
{
var response = await http.PutAsJsonAsync(url, content);
return await HandleResponse<T>(response);
}
catch (Exception ex)
{
return ResponseResult<T>.Failure(ex.Message);
}
}
private static async Task<ResponseResult<T>> HandleResponse<T>(
HttpResponseMessage response)
{
if (response.IsSuccessStatusCode)
{
var data = await response.Content
.ReadFromJsonAsync<T>();
return ResponseResult<T>.Success(data!);
}
var problem = await response.Content
.ReadFromJsonAsync<ProblemDetails>();
return ResponseResult<T>.Failure(
problem?.Detail ?? $"HTTP {(int)response.StatusCode}");
}
}
public static IServiceCollection AddGatewayClients(
this IServiceCollection services, IConfiguration configuration)
{
var gatewayUrl = configuration["GatewayUrl"]!;
services.AddHttpClient<OrderGateway>(client =>
{
client.BaseAddress = new Uri(gatewayUrl);
});
return services;
}
| Anti-Pattern | Correct Approach |
|---|---|
| Direct HttpClient in components | Use gateway facade classes |
| No error handling in HTTP calls | Wrap in try/catch, return ResponseResult |
| Hardcoded URLs | Use BaseRoute constants and configuration |
| Missing serialization handling | Use HttpExtensions for consistency |
# Find gateway classes
grep -r "Gateway.*HttpClient\|Management.*HttpClient" --include="*.cs" src/ControlPanel/
# Find HttpExtensions
grep -r "HttpExtensions\|GetAsync<\|PostAsJsonAsync<" --include="*.cs" src/ControlPanel/
# Find gateway registration
grep -r "AddHttpClient<.*Gateway" --include="*.cs" src/ControlPanel/
HttpExtensions for all HTTP callsResponseResult<T> from all management methods