Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/docs/usage/client.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 3 additions & 5 deletions src/RestSharp/RestClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -97,7 +99,6 @@ HttpClient GetClient() {
// We will use Options.Timeout in ExecuteAsInternalAsync method
httpClient.Timeout = Timeout.InfiniteTimeSpan;

ConfigureDefaultParameters(options);
configureDefaultHeaders?.Invoke(httpClient.DefaultRequestHeaders);
return httpClient;
}
Expand Down Expand Up @@ -185,10 +186,7 @@ public RestClient(
var opt = options ?? new RestClientOptions();
Options = new(opt);
DefaultParameters = new(Options);

if (options != null) {
ConfigureDefaultParameters(options);
}
ConfigureDefaultParameters(opt);
}

/// <summary>
Expand Down
41 changes: 41 additions & 0 deletions test/RestSharp.Tests/RestClientTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,47 @@ 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";

// 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 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(
restClient.DefaultParameters,
parameter => parameter is { Type: ParameterType.HttpHeader, Name: KnownHeaders.UserAgent, Value: string valueAsString } &&
valueAsString == new RestClientOptions().UserAgent
);
}

[Fact]
public void Should_not_set_expect_continue_on_shared_http_client_default_headers() {
// arrange
Expand Down
Loading