From 0d3b326665fc12c97fdfbf98307ad7f05685a11a Mon Sep 17 00:00:00 2001 From: Pierre Dupont Date: Tue, 9 Jun 2026 10:04:25 +0200 Subject: [PATCH 1/2] Fix DefaultParameters not set up using a cached client instance while useClientFactory: true --- src/RestSharp/RestClient.cs | 2 +- test/RestSharp.Tests/RestClientTests.cs | 36 +++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/RestSharp/RestClient.cs b/src/RestSharp/RestClient.cs index 9ab456975..fafa91890 100644 --- a/src/RestSharp/RestClient.cs +++ b/src/RestSharp/RestClient.cs @@ -86,6 +86,7 @@ public RestClient( HttpClient = GetClient(); } + ConfigureDefaultParameters(options); return; HttpClient GetClient() { @@ -97,7 +98,6 @@ HttpClient GetClient() { // We will use Options.Timeout in ExecuteAsInternalAsync method httpClient.Timeout = Timeout.InfiniteTimeSpan; - ConfigureDefaultParameters(options); configureDefaultHeaders?.Invoke(httpClient.DefaultRequestHeaders); return httpClient; } diff --git a/test/RestSharp.Tests/RestClientTests.cs b/test/RestSharp.Tests/RestClientTests.cs index 2c82278f1..e614b5813 100644 --- a/test/RestSharp.Tests/RestClientTests.cs +++ b/test/RestSharp.Tests/RestClientTests.cs @@ -124,6 +124,42 @@ public void ConfigureDefaultParameters_sets_user_agent_given_httpClient_instance Assert.Empty(httpClient.DefaultRequestHeaders.UserAgent); } + [Fact] + public void ConfigureDefaultParameters_sets_user_agent_using_factory_twice() { + // arrange + const string expectedAgentString = "Agent/1.0"; + + var clientOptions = new RestClientOptions + { + BaseUrl = new Uri("https://localhost:8888"), + UserAgent = expectedAgentString + }; + + // act + using var firstRestClient = new RestClient(clientOptions, useClientFactory: true); + using var secondRestClient = new RestClient(clientOptions, useClientFactory: true); + + //assert + Assert.Single( + firstRestClient.DefaultParameters, + parameter => parameter is + { + Type: ParameterType.HttpHeader, + Name: KnownHeaders.UserAgent, + Value: expectedAgentString + } + ); + Assert.Single( + secondRestClient.DefaultParameters, + parameter => parameter is + { + Type: ParameterType.HttpHeader, + Name: KnownHeaders.UserAgent, + Value: expectedAgentString + } + ); + } + [Fact] public void Should_not_set_expect_continue_on_shared_http_client_default_headers() { // arrange From d85a4f34cead6e87cfe81328c17c1e5b155a4f83 Mon Sep 17 00:00:00 2001 From: Alexey Zimarev Date: Wed, 2 Sep 2026 12:30:17 +0200 Subject: [PATCH 2/2] Address review findings on #2390 - Move ConfigureDefaultParameters next to DefaultParameters init so it reads as per-instance setup and runs before the HttpClient is committed to the factory cache (a throwing ctor no longer leaks a cache entry) - Call ConfigureDefaultParameters unconditionally in the HttpClient ctor so RestClient(httpClient, options: null) gets the default User-Agent, matching the delegating RestClient(httpClient) overload - Harden the regression test: assert the second client actually reuses the cached HttpClient, dedupe the assertions, follow .editorconfig - Add test for the null-options ctor path - Docs: UserAgent is no longer ignored by the simple client factory Co-Authored-By: Claude Fable 5 --- docs/docs/usage/client.md | 3 +- src/RestSharp/RestClient.cs | 8 ++-- test/RestSharp.Tests/RestClientTests.cs | 49 ++++++++++++++----------- 3 files changed, 32 insertions(+), 28 deletions(-) diff --git a/docs/docs/usage/client.md b/docs/docs/usage/client.md index 97af9fce5..6e95e130a 100644 --- a/docs/docs/usage/client.md +++ b/docs/docs/usage/client.md @@ -48,11 +48,12 @@ Another way to create the client instance is to use a simple client factory. The * `ClientCertificates` * `MaxRedirects` * `Timeout` -* `UserAgent` * `Expect100Continue` Constructor parameters to configure the `HttpMessageHandler` and default `HttpClient` headers configuration are also ignored for the cached instance as the factory only configures the handler once. +The `UserAgent` option is not affected by caching: it is added to each `RestClient` instance's default parameters and applied per request, so every client gets its own `User-Agent` header even when the underlying `HttpClient` is reused. + You need to set the `useClientFactory` parameter to `true` in the `RestClient` constructor to enable the factory. ```csharp diff --git a/src/RestSharp/RestClient.cs b/src/RestSharp/RestClient.cs index fafa91890..9762e63ec 100644 --- a/src/RestSharp/RestClient.cs +++ b/src/RestSharp/RestClient.cs @@ -76,6 +76,8 @@ public RestClient( ConfigureSerializers(configureSerialization); Options = new(options); DefaultParameters = new(Options); + // Must run per RestClient instance, not inside GetClient: the factory may return a cached HttpClient without invoking GetClient + ConfigureDefaultParameters(options); if (useClientFactory) { _disposeHttpClient = false; @@ -86,7 +88,6 @@ public RestClient( HttpClient = GetClient(); } - ConfigureDefaultParameters(options); return; HttpClient GetClient() { @@ -185,10 +186,7 @@ public RestClient( var opt = options ?? new RestClientOptions(); Options = new(opt); DefaultParameters = new(Options); - - if (options != null) { - ConfigureDefaultParameters(options); - } + ConfigureDefaultParameters(opt); } /// diff --git a/test/RestSharp.Tests/RestClientTests.cs b/test/RestSharp.Tests/RestClientTests.cs index e614b5813..ea4f9a34a 100644 --- a/test/RestSharp.Tests/RestClientTests.cs +++ b/test/RestSharp.Tests/RestClientTests.cs @@ -129,34 +129,39 @@ public void ConfigureDefaultParameters_sets_user_agent_using_factory_twice() { // arrange const string expectedAgentString = "Agent/1.0"; - var clientOptions = new RestClientOptions - { - BaseUrl = new Uri("https://localhost:8888"), - UserAgent = expectedAgentString - }; + // The base URL is unique to this test to keep the process-wide factory cache isolated from other tests + var clientOptions = new RestClientOptions { BaseUrl = new Uri("https://localhost:8888"), UserAgent = expectedAgentString }; // act - using var firstRestClient = new RestClient(clientOptions, useClientFactory: true); + using var firstRestClient = new RestClient(clientOptions, useClientFactory: true); using var secondRestClient = new RestClient(clientOptions, useClientFactory: true); + //assert + secondRestClient.HttpClient.Should().BeSameAs(firstRestClient.HttpClient, "the regression only manifests on a factory cache hit"); + AssertHasUserAgent(firstRestClient); + AssertHasUserAgent(secondRestClient); + return; + + static void AssertHasUserAgent(RestClient restClient) + => Assert.Single( + restClient.DefaultParameters, + parameter => parameter is { Type: ParameterType.HttpHeader, Name: KnownHeaders.UserAgent, Value: expectedAgentString } + ); + } + + [Fact] + public void ConfigureDefaultParameters_sets_user_agent_given_httpClient_and_null_options() { + // arrange + var httpClient = new HttpClient(); + + // act + using var restClient = new RestClient(httpClient, options: null); + //assert Assert.Single( - firstRestClient.DefaultParameters, - parameter => parameter is - { - Type: ParameterType.HttpHeader, - Name: KnownHeaders.UserAgent, - Value: expectedAgentString - } - ); - Assert.Single( - secondRestClient.DefaultParameters, - parameter => parameter is - { - Type: ParameterType.HttpHeader, - Name: KnownHeaders.UserAgent, - Value: expectedAgentString - } + restClient.DefaultParameters, + parameter => parameter is { Type: ParameterType.HttpHeader, Name: KnownHeaders.UserAgent, Value: string valueAsString } && + valueAsString == new RestClientOptions().UserAgent ); }