Skip to content

Commit 0527b8d

Browse files
committed
Refresh DNS in WLedClient(string) via SocketsHttpHandler
Use a SocketsHttpHandler with a 2-minute PooledConnectionLifetime for the self-owned HttpClient on modern runtimes so a long-lived client picks up DNS/IP changes, falling back to HttpClientHandler on netstandard2.0. Expose CreateDefaultHandler internally for testing and document the behaviour (fixes #8).
1 parent 374b86a commit 0527b8d

5 files changed

Lines changed: 59 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ rather than deprecated, so consuming code must be updated.
4848
- **`ColorTemperature.Kelvin` range widened to `1000–20000 K`** to match the docs' forward-
4949
compatible guidance, with a new `ColorTemperature.KelvinUnchecked(int)` escape hatch for
5050
values outside that range.
51+
- **`WLedClient(string)` now refreshes DNS.** The convenience constructor's self-owned
52+
`HttpClient` uses a `SocketsHttpHandler` with a bounded `PooledConnectionLifetime` (2 minutes)
53+
on modern runtimes, so a long-lived client picks up DNS/IP changes instead of pinning a stale
54+
connection (fixes [#8](https://github.com/kevbite/WLED.NET/issues/8)). The `netstandard2.0`
55+
build falls back to `HttpClientHandler`; use `IHttpClientFactory`/DI there.
5156

5257
### Added
5358

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@ services.AddWledClient("http://office-computer-wled/");
4141
services.AddWledClient(client => client.BaseAddress = new Uri("http://office-computer-wled/"));
4242
```
4343

44+
The `WLedClient(string)` constructor owns its `HttpClient` and uses a `SocketsHttpHandler`
45+
with a bounded `PooledConnectionLifetime`, so a long-lived client still picks up DNS changes
46+
(e.g. a WLED device that gets a new IP). For applications, registering via
47+
`IHttpClientFactory`/DI as above remains the recommended approach.
48+
4449
### Quick commands
4550

4651
Common operations have first-class "intent" methods:

src/Kevsoft.WLED/Kevsoft.WLED.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@
2222
<None Include="../../icon.png" Pack="true" Visible="false" PackagePath="" />
2323
</ItemGroup>
2424

25+
<ItemGroup>
26+
<InternalsVisibleTo Include="Kevsoft.WLED.Tests" />
27+
</ItemGroup>
28+
2529
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
2630
<PackageReference Include="System.Net.Http.Json" Version="6.0.0" />
2731
<PackageReference Include="System.Text.Json" Version="8.0.5" />

src/Kevsoft.WLED/WLedClient.cs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ public WLedClient(HttpMessageHandler httpMessageHandler, string baseUri)
99
{
1010
}
1111

12-
public WLedClient(string baseUri) : this(new HttpClientHandler(), baseUri)
12+
public WLedClient(string baseUri) : this(CreateDefaultHandler(), baseUri)
1313
{
1414
}
1515

@@ -38,6 +38,25 @@ private static HttpClient CreateClient(HttpMessageHandler httpMessageHandler, st
3838
return client;
3939
}
4040

41+
/// <summary>
42+
/// Creates the default <see cref="HttpMessageHandler"/> used when the client owns its own
43+
/// <see cref="HttpClient"/>. On modern runtimes this is a <c>SocketsHttpHandler</c> with a bounded
44+
/// <c>PooledConnectionLifetime</c> so pooled connections — and therefore DNS — are refreshed
45+
/// periodically. See
46+
/// https://learn.microsoft.com/dotnet/fundamentals/networking/http/httpclient-guidelines#dns-behavior.
47+
/// </summary>
48+
internal static HttpMessageHandler CreateDefaultHandler()
49+
{
50+
#if NETSTANDARD2_0
51+
return new HttpClientHandler();
52+
#else
53+
return new SocketsHttpHandler
54+
{
55+
PooledConnectionLifetime = TimeSpan.FromMinutes(2)
56+
};
57+
#endif
58+
}
59+
4160
public Task<WLedRootResponse> Get(CancellationToken cancellationToken = default)
4261
=> GetJson<WLedRootResponse>("json", cancellationToken);
4362

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using System.Net.Http;
2+
3+
namespace Kevsoft.WLED.Tests;
4+
5+
public class WLedClientConstructionTests
6+
{
7+
[Fact]
8+
public void StringConstructorSucceeds()
9+
{
10+
var act = () => new WLedClient("http://wled.local/");
11+
12+
act.Should().NotThrow();
13+
}
14+
15+
#if !NETSTANDARD2_0
16+
[Fact]
17+
public void DefaultHandlerRefreshesPooledConnectionsToAvoidStaleDns()
18+
{
19+
var handler = WLedClient.CreateDefaultHandler();
20+
21+
handler.Should().BeOfType<SocketsHttpHandler>()
22+
.Which.PooledConnectionLifetime.Should().Be(TimeSpan.FromMinutes(2));
23+
}
24+
#endif
25+
}

0 commit comments

Comments
 (0)