Skip to content

Support per-client HttpClient configuration in AsHttpClient() #10

Description

@ChrisonSimtian

Summary

Today the .AsHttpClient() / .AsHttpClient(name) selectors register every scanned class as a typed HttpClient, but they don't offer a way to give each client its own configuration. Consumers either point everything at a single pre-registered named client (shared base address/handlers) or get a default client per type with no configuration hook.

This is precisely the limitation the Scrutor maintainer raised when declining native support in khellang/Scrutor#180:

convention registration gives every scanned client the same Action<HttpClient> config … at that point I don't see much value in scanning and registering based on convention.

Closing that gap would make the library useful for fleets of clients that share a scheme but not identical config (per-client base path, headers, timeouts, resilience).

Proposed API (sketch)

Add overloads that thread a configuration callback through to the underlying AddHttpClient<TClient,TImplementation>(...):

// Configure by client type — invoked once per scanned (service, implementation) pair.
public static IServiceTypeSelector AsHttpClient(
    this IServiceTypeSelector selector,
    Action<IServiceProvider, Type, HttpClient> configureClient);

// Named base client + per-client tweaks on top.
public static IServiceTypeSelector AsHttpClient(
    this IServiceTypeSelector selector,
    string name,
    Action<IServiceProvider, Type, HttpClient> configureClient);

The Type argument lets a single callback branch per client (e.g. derive the base path from the client name/attribute), keeping the convention-registration ergonomics while allowing divergence.

Considerations

  • Overload resolution / reflection: AsHttpClient already resolves the right AddHttpClient<,> generic via reflection; the config-taking overloads ((IServiceCollection, Action<HttpClient>), (IServiceCollection, string, Action<HttpClient>), and the IServiceProvider-aware variants) would be matched the same way. Keep the current shape-matching logic in HttpClientRegistrationStrategy general enough to select them.
  • Trim/AOT: stays behind the existing [RequiresUnreferencedCode]/[RequiresDynamicCode] annotations — no change to the AOT story.
  • Public API: additive; existing overloads unchanged. Would need new PublicApiGenerator baseline entries + specs (a per-type config callback firing with the expected HttpClient).
  • Design question: is a per-Type discriminator enough, or do we also want an attribute-driven config (e.g. [HttpClient(BaseAddress = "...")]) read at registration time? The attribute route overlaps with the source-generator direction we deliberately deferred.

Priority

Future enhancement — not urgent. Filed to capture the idea; the library is fully functional without it (named-client pattern covers the common case).

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions