Skip to content

Commit 3cf97d0

Browse files
docs: beautify README with badges + real usage (#8)
- Badge row matching the TvdbClient sibling: NuGet version, downloads, Build & Test, Built with Fallout, License. - Rewrite from the terse stub into proper docs: what it does (+ the Scrutor #180 lineage), install, named vs unnamed .AsHttpClient() overloads with a worked example, compatibility (Scrutor 7.x, net8.0 + netstandard2.0), an honest trimming/AOT note, and the Fallout build commands. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 1571247 commit 3cf97d0

1 file changed

Lines changed: 88 additions & 14 deletions

File tree

‎README.md‎

Lines changed: 88 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,98 @@
11
# Scrutor.Extensions.HttpClient
2-
A solution for https://github.com/khellang/Scrutor/issues/180 baked into a Nuget Package
2+
3+
[![NuGet](https://img.shields.io/nuget/v/Scrutor.Extensions.HttpClient.svg)](https://www.nuget.org/packages/Scrutor.Extensions.HttpClient/)
4+
[![Downloads](https://img.shields.io/nuget/dt/Scrutor.Extensions.HttpClient.svg)](https://www.nuget.org/packages/Scrutor.Extensions.HttpClient/)
5+
[![Build & Test](https://github.com/Chrison-dev/Scrutor.Extensions.HttpClient/actions/workflows/build.yml/badge.svg)](https://github.com/Chrison-dev/Scrutor.Extensions.HttpClient/actions/workflows/build.yml)
6+
[![Built with Fallout](https://img.shields.io/badge/built%20with-Fallout-8A2BE2)](https://github.com/Fallout-build/Fallout)
7+
[![License](https://img.shields.io/github/license/Chrison-dev/Scrutor.Extensions.HttpClient.svg)](LICENSE)
8+
9+
A tiny companion for [Scrutor](https://github.com/khellang/Scrutor) that lets its
10+
assembly-scanning register each matched class as a **typed
11+
[`HttpClient`](https://learn.microsoft.com/dotnet/core/extensions/httpclient-factory#typed-clients)**
12+
(via `IHttpClientFactory`) instead of a plain service — the one thing Scrutor
13+
[deliberately doesn't do out of the box](https://github.com/khellang/Scrutor/issues/180).
14+
15+
```csharp
16+
services.Scan(scan => scan
17+
.FromAssemblyOf<IWeatherClient>()
18+
.AddClasses(c => c.AssignableTo<IApiClient>())
19+
.AsMatchingInterface()
20+
.AsHttpClient("weather")); // ← every scanned client becomes a typed HttpClient
21+
```
22+
23+
## Install
24+
25+
```sh
26+
dotnet add package Scrutor.Extensions.HttpClient
27+
```
328

429
## Usage
530

6-
1. Inject your Http Client as a named Client
7-
2. Make sure that all your Api Clients are assignable to a common interface
8-
3. Register all your Api Clients with Scrutor.Extensions.HttpClient
31+
1. Register a **named** `HttpClient` with your shared configuration.
32+
2. Make your API clients implement a common marker interface (and, for
33+
`.AsMatchingInterface()`, an `I{ClassName}` interface each).
34+
3. Scan for them and finish the chain with `.AsHttpClient("<name>")`.
935

1036
```csharp
11-
/* Inject named HttpClient */
12-
services.AddHttpClient("MyHttpClient", client =>
37+
// 1. A named client carrying the shared config (base address, handlers, Polly, …).
38+
services.AddHttpClient("weather", client =>
1339
{
14-
client.BaseAddress = new Uri("https://api.example.com");
40+
client.BaseAddress = new Uri("https://api.example.com");
1541
});
1642

17-
/* Inject all implementations of IMyHttpApiClient */
43+
// 2 + 3. Register every IApiClient implementation as a typed client of "weather".
1844
services.Scan(scan => scan
19-
.FromCallingAssembly()
20-
.AddClasses(classes => classes.AssignableTo<IMyHttpApiClient>())
21-
.AsMatchingInterface()
22-
.AsHttpClient("MyHttpClient")
23-
);
24-
```
45+
.FromAssemblyOf<IWeatherClient>()
46+
.AddClasses(classes => classes.AssignableTo<IApiClient>())
47+
.AsMatchingInterface()
48+
.AsHttpClient("weather"));
49+
```
50+
51+
Now each scanned client is resolved from `IHttpClientFactory` with the `"weather"`
52+
client's configuration injected:
53+
54+
```csharp
55+
public sealed class WeatherClient(HttpClient http) : IWeatherClient
56+
{
57+
public Task<Forecast?> GetAsync(string city) =>
58+
http.GetFromJsonAsync<Forecast>($"forecast/{city}");
59+
}
60+
```
61+
62+
### Overloads
63+
64+
| Call | Behaviour |
65+
|---|---|
66+
| `.AsHttpClient("name")` | Registers each scanned class as a typed client bound to the **named** client `"name"` — they share its configuration. |
67+
| `.AsHttpClient()` | Registers each scanned class as a typed client with **its own** default client (named after the service type). |
68+
69+
Both are `IServiceTypeSelector` extensions, so they slot onto the end of any Scrutor
70+
`.Scan(...)` chain (`.AsMatchingInterface()`, `.AsSelf()`, `.As<T>()`, …).
71+
72+
## Compatibility
73+
74+
- **Scrutor 7.x** — the package major tracks Scrutor's major (`7.x` ↔ Scrutor 7.x).
75+
- Targets **`net8.0`** and **`netstandard2.0`** (so it's usable from .NET Framework 4.6.2+,
76+
.NET Core 2.0+, and modern .NET alike).
77+
78+
### Trimming / AOT
79+
80+
This bridges Scrutor's **runtime** assembly scan and closes the generic
81+
`AddHttpClient<TClient,TImplementation>` over the scanned types via reflection, so it
82+
is **not** trim- or Native-AOT-safe. The public methods are annotated with
83+
`[RequiresUnreferencedCode]` / `[RequiresDynamicCode]`, so a trimmed/AOT build gets an
84+
honest warning at the call site rather than silent breakage.
85+
86+
## Building
87+
88+
CI is defined in C# with [Fallout](https://github.com/Fallout-build/Fallout) (a NUKE
89+
fork); the GitHub Actions workflow is generated from the build, never hand-edited.
90+
91+
```sh
92+
./build.cmd Test # run the spec suite
93+
./build.cmd Pack # test + pack the NuGet package
94+
```
95+
96+
## License
97+
98+
[MIT](LICENSE)

0 commit comments

Comments
 (0)