К основному содержанию
скилл CX Codex

httpclient-factory — скилл для Claude Code: обзор и запуск

Скилл обучает ассистента конфигурировать IHttpClientFactory и типовые HTTP-клиенты для .NET 10. Помогает настроить политики устойчивости и избежать исчерпания сокетов.

Установить в Claude Code · Через Skills CLI (Vercel) Все способы и платформы ↓
npx skills add codewithmukesh/dotnet-claude-kit --skill httpclient-factory -a claude-code
Открыть на GitHub

Что делает httpclient-factory

Скилл задаёт правила работы с сетевыми вызовами в .NET 10, запрещая создавать экземпляры new HttpClient() вручную под каждый запрос. Создание клиентов напрямую приводит к исчерпанию доступных сокетов и игнорирует обновление DNS-записей. Вместо этого инструмент продвигает регистрацию через AddAsKeyed() или IHttpClientFactory, предотвращая утечку обработчиков внутри синглтонов.

Внутри заложены готовые шаблоны для цепочек DelegatingHandler, проброса токенов авторизации и заголовка X-Correlation-Id. Для устойчивости внешних вызовов используется библиотека Microsoft.Extensions.Http.Resilience с вызовом AddStandardResilienceHandler(). Он настраивает пять стратегий: лимит на 1000 параллельных запросов, таймауты, автоматические повторы с джиттером и размыкатель цепи при 10% ошибок. Захват типизированных клиентов в singleton-сервисах сломает ротацию обработчиков, поэтому скилл настаивает на keyed-клиентах.

Какие задачи решает

  • устранить исчерпание сокетов при частых сетевых вызовах
  • настроить политики повторов и circuit breaker через AddStandardResilienceHandler
  • внедрить передачу токенов авторизации и заголовка X-Correlation-Id через DelegatingHandler
  • протестировать HTTP-клиенты с помощью MockHttpHandler

Примеры запросов агенту

  • Настрой именованный HTTP-клиент для платёжного шлюза с AddStandardResilienceHandler в .NET 10.
  • Добавь DelegatingHandler для автоматической подстановки токена авторизации Bearer.
  • Переведи регистрацию HttpClient на AddAsKeyed, чтобы безопасно внедрять его в эндпоинты.

Как установить httpclient-factory

1Через Skills CLI (Vercel)

npx skills add codewithmukesh/dotnet-claude-kit --skill httpclient-factory -a claude-code

2Вручную: положить файлы

~/.claude/skills/httpclient-factory/SKILL.md

Папка скилла целиком; для одного проекта — .claude/skills/httpclient-factory/

По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов

Вопросы о httpclient-factory

Как установить httpclient-factory в Claude Code?

Выполните в терминале команду npx skills add codewithmukesh/dotnet-claude-kit --skill httpclient-factory -a claude-code.

Зачем нужен скилл httpclient-factory?

Он помогает агенту генерировать надёжный код сетевых запросов в .NET 10, исключая ручное создание HttpClient и утечки сокетов.

Какие параметры задаёт AddStandardResilienceHandler по умолчанию?

Метод включает пять механизмов: ограничение до 1000 одновременных запросов, общий таймаут на 30 секунд, таймаут попытки на 10 секунд, 3 повторные попытки с экспоненциальной задержкой и размыкатель цепи при 10% ошибок.

Исходный текст

SKILL.md · MIT
---
name: httpclient-factory
description: >
  IHttpClientFactory and typed HTTP clients for .NET 10 applications. Covers
  named/typed/keyed clients, DelegatingHandlers, resilience with
  Microsoft.Extensions.Http.Resilience, and testing patterns.
  Load this skill when configuring HTTP clients, adding retry/circuit breaker
  policies, or when the user mentions "HttpClient", "IHttpClientFactory",
  "AddHttpClient", "typed client", "named client", "DelegatingHandler",
  "resilience", "retry", "circuit breaker", "hedging", "Polly",
  "AddStandardResilienceHandler", "socket exhaustion", or "Refit".
---

# HttpClient Factory

## Core Principles

1. **Never `new HttpClient()` per request** — Raw `HttpClient` creation causes socket exhaustion under load and ignores DNS changes. Use `IHttpClientFactory` to manage handler lifetimes.
2. **Keyed clients over typed clients** — Keyed DI (`.AddAsKeyed()`) is the recommended pattern in .NET 10. Typed clients captured in singletons silently break handler rotation.
3. **Resilience is not optional** — Every external HTTP call needs retry, circuit breaker, and timeout. `AddStandardResilienceHandler()` provides sensible defaults in one line.
4. **DelegatingHandlers for cross-cutting concerns** — Auth tokens, correlation IDs, and logging belong in the handler pipeline, not scattered across service methods.

## Patterns

### Named Client with Resilience

```csharp
builder.Services.AddHttpClient("github", client =>
{
    client.BaseAddress = new Uri("https://api.github.com/");
    client.DefaultRequestHeaders.UserAgent.ParseAdd("MyApp/1.0");
    client.DefaultRequestHeaders.Accept.Add(
        new MediaTypeWithQualityHeaderValue("application/json"));
})
.AddStandardResilienceHandler();

// Usage via factory
public sealed class GitHubService(IHttpClientFactory factory)
{
    public async Task<Repo?> GetRepoAsync(string owner, string name, CancellationToken ct)
    {
        var client = factory.CreateClient("github");
        return await client.GetFromJsonAsync<Repo>($"repos/{owner}/{name}", ct);
    }
}
```

### Keyed Client (Recommended in .NET 10)

Combines named client configurability with direct injection. No string lookups.

```csharp
builder.Services.AddHttpClient("payments", client =>
{
    client.BaseAddress = new Uri("https://api.payments.example.com/");
})
.AddStandardResilienceHandler()
.AddAsKeyed();  // Register as keyed scoped service

// Inject directly — no IHttpClientFactory needed
app.MapPost("/charge", async (
    [FromKeyedServices("payments")] HttpClient httpClient,
    ChargeRequest request,
    CancellationToken ct) =>
{
    var response = await httpClient.PostAsJsonAsync("charges", request, ct);
    return response.IsSuccessStatusCode
        ? TypedResults.Ok()
        : TypedResults.Problem("Payment failed");
});
```

Global opt-in: `builder.Services.ConfigureHttpClientDefaults(b => b.AddAsKeyed());`

### Standard Resilience Handler

`AddStandardResilienceHandler()` chains 5 strategies:

| Strategy | Default |
|----------|---------|
| Rate limiter | 1000 concurrent requests |
| Total timeout | 30 seconds |
| Retry | 3 retries, exponential backoff with jitter |
| Circuit breaker | Opens at 10% failure rate |
| Attempt timeout | 10 seconds per attempt |

```csharp
builder.Services.AddHttpClient("api")
    .AddStandardResilienceHandler(options =>
    {
        options.Retry.MaxRetryAttempts = 5;
        options.Retry.Delay = TimeSpan.FromSeconds(1);
        options.TotalRequestTimeout.Timeout = TimeSpan.FromSeconds(60);
        options.AttemptTimeout.Timeout = TimeSpan.FromSeconds(15);

        // Disable retries for non-idempotent methods
        options.Retry.DisableForUnsafeHttpMethods();
    });
```

### DelegatingHandler for Auth Token Injection

```csharp
public sealed class AuthenticationHandler(ITokenService tokenService)
    : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var token = await tokenService.GetAccessTokenAsync(cancellationToken);
        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
        return await base.SendAsync(request, cancellationToken);
    }
}

// Registration
builder.Services.AddTransient<AuthenticationHandler>();
builder.Services.AddHttpClient("api")
    .AddHttpMessageHandler<AuthenticationHandler>()
    .AddStandardResilienceHandler();
```

### DelegatingHandler for Correlation ID Propagation

```csharp
public sealed class CorrelationIdHandler(IHttpContextAccessor httpContextAccessor)
    : DelegatingHandler
{
    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        if (httpContextAccessor.HttpContext?.Request.Headers
                .TryGetValue("X-Correlation-Id", out var correlationId) is true)
        {
            request.Headers.Add("X-Correlation-Id", correlationId.ToString());
        }
        return base.SendAsync(request, cancellationToken);
    }
}
```

### SocketsHttpHandler Configuration

```csharp
builder.Services.AddHttpClient("advanced")
    .UseSocketsHttpHandler((handler, _) =>
    {
        handler.PooledConnectionLifetime = TimeSpan.FromMinutes(2);
        handler.PooledConnectionIdleTimeout = TimeSpan.FromMinutes(1);
        handler.MaxConnectionsPerServer = 100;
        handler.AutomaticDecompression =
            DecompressionMethods.GZip | DecompressionMethods.Brotli;
    });
```

### Testing with Mock Handler

```csharp
public sealed class MockHttpHandler(
    HttpStatusCode statusCode,
    string content) : HttpMessageHandler
{
    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        return Task.FromResult(new HttpResponseMessage(statusCode)
        {
            Content = new StringContent(content, Encoding.UTF8, "application/json")
        });
    }
}

// In test
var handler = new MockHttpHandler(HttpStatusCode.OK, """{"id":1}""");
var client = new HttpClient(handler) { BaseAddress = new Uri("https://api.test/") };
var service = new MyService(client);
```

## Anti-patterns

### Don't Create HttpClient Per Request

```csharp
// BAD — socket exhaustion under load, ignores DNS changes
public async Task<string> GetDataAsync()
{
    using var client = new HttpClient();
    return await client.GetStringAsync("https://api.example.com/data");
}

// GOOD — factory-managed
public async Task<string> GetDataAsync(CancellationToken ct)
{
    var client = factory.CreateClient("api");
    return await client.GetStringAsync("https://api.example.com/data", ct);
}
```

### Don't Capture Typed Clients in Singletons

```csharp
// BAD — transient HttpClient captured by singleton defeats handler rotation
services.AddSingleton<MySingletonService>();
services.AddHttpClient<MySingletonService>();

// GOOD — use keyed client or IHttpClientFactory in singletons
services.AddSingleton<MySingletonService>();
services.AddHttpClient("myservice").AddAsKeyed(ServiceLifetime.Singleton);
```

### Don't Mutate DefaultRequestHeaders on Shared Clients

```csharp
// BAD — not thread-safe
httpClient.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", token);

// GOOD — use DelegatingHandler or per-request HttpRequestMessage
using var request = new HttpRequestMessage(HttpMethod.Get, "/api/data");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
await httpClient.SendAsync(request, ct);
```

### Don't Forget CancellationToken

```csharp
// BAD — no cancellation support
var result = await httpClient.GetFromJsonAsync<Order>("/orders/1");

// GOOD — always pass CancellationToken
var result = await httpClient.GetFromJsonAsync<Order>("/orders/1", cancellationToken);
```

### Don't Stack Multiple Resilience Handlers

```csharp
// BAD — conflicting resilience strategies
builder.AddStandardResilienceHandler();
builder.AddStandardHedgingHandler();

// GOOD — one standard handler, or a custom pipeline
builder.AddStandardResilienceHandler();
```

## Decision Guide

| Scenario | Recommendation |
|----------|---------------|
| New .NET 10 project | Keyed clients with `AddAsKeyed()` |
| Singleton service needs HttpClient | Named client via `IHttpClientFactory` or keyed singleton |
| External API calls | `AddStandardResilienceHandler()` on every client |
| Auth token injection | `DelegatingHandler` registered with `AddHttpMessageHandler` |
| Hedging (parallel requests) | `AddStandardHedgingHandler()` for latency-sensitive calls |
| Non-idempotent methods | `DisableForUnsafeHttpMethods()` on retry options |
| Custom retry logic | `AddResilienceHandler("name", builder => ...)` |
| Connection pooling control | `UseSocketsHttpHandler` with `PooledConnectionLifetime` |
| API client generation | Refit with `AddRefitClient<T>()` |
| Integration testing | Custom `HttpMessageHandler` or `MockHttpMessageHandler` |

© codewithmukesh · MIT · codewithmukesh/dotnet-claude-kit

Похожие скиллы

Всё по теме «Бэкенд и API» →
fetch-and-send-data dotnet Помогает загружать и отправлять данные через API в Blazor-компонентах. Нужен для настройки HttpClient, состояний загрузки и обработки ошибок. CX Codex +1 3 100установок dotnet-backend-patterns Seth Hobson Скилл для разработки на C# и .NET: паттерны асинхронного кода, внедрение зависимостей, Entity Framework Core, кэширование и тестирование. Нужен, если вы пишете backend API, MCP-серверы или рецензируете код на C#. CX Codex 19 076установок csharp-testing affaan-m Скилл для написания и разбора тестов на C# и .NET: xUnit, FluentAssertions, моки, интеграционные тесты. CX Codex +1 4 500установок testability-obstacle dotnet Вводит минимальный шов в продакшен-код C#/.NET, чтобы тест перестал зависеть от реального времени, файлов и случайности. CX Codex +1 2 500установок dotnet Mindrally Задаёт агенту правила C#, ASP.NET Core и Entity Framework Core: структура проекта, async/await, DI, кэш, тесты. CX Codex +1 724установок dependency-injection-patterns Aaronontheweb Скилл учит раскладывать регистрации сервисов в ASP.NET Core по расширениям IServiceCollection, чтобы Program.cs не распухал. CX Codex +1 668установок

Из того же набора46

scalar Скилл подсказывает агенту, как подключить Scalar вместо Swagger UI в приложении на .NET 10 и настроить темы, авторизацию и несколько документов. CX Codex +1 2 800установок opentelemetry Скилл настраивает трассировку, метрики и логи OpenTelemetry в .NET 10 через единый вызов с OTLP-экспортом. CX Codex +1 2 800установок messaging Скилл для .NET-проектов: подсказывает, как настроить Wolverine или MassTransit, outbox, саги и брокеры RabbitMQ и Azure Service Bus. CX Codex +1 2 800установок project-structure Скилл задаёт агенту правила раскладки .NET-решения: центральные версии пакетов, общие свойства сборки, формат .slnx и именование проектов. CX Codex +1 2 800установок de-sloppify Наводит порядок в .NET-коде по семи шагам: от форматирования до передачи CancellationToken. Нужен перед релизом, после крупных изменений или обновления зависимостей. CX Codex +1 2 800установок logging Скилл про наблюдаемость в .NET 10: разводит liveness и readiness, прокидывает correlation ID и задаёт уровни логов. CX Codex +1 2 800установок ci-cd Скилл помогает создавать YAML-пайплайны для проектов на .NET. Пригодится для быстрой настройки GitHub Actions и Azure DevOps с этапами сборки, тестов и публикации. CX Codex +1 2 800установок resilience Скилл для ИИ-агента, который подсказывает, как строить отказоустойчивые вызовы в .NET 10 на Polly v8: retry, circuit breaker, таймауты, fallback. CX Codex +1 2 800установок

Спонсоры проекта

Компании, которые помогают держать аналитику открытой