diff --git a/docs/usage.md b/docs/usage.md index 424582f78..b84918e2a 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -594,7 +594,7 @@ One way of doing it is to use `RestClient` constructors that accept an instance - `BaseAddress` will be used to set the base address of the `HttpClient` instance if base address is not set there already. - `MaxTimeout` -- `UserAgent` will be set if the `User-Agent` header is not set on the `HttpClient` instance already. +- `UserAgent` will be added to the `RestClient.DefaultParameters` list as a HTTP header. This will be added to each request made by the `RestClient`, and the `HttpClient` instance will not be modified. This is to allow the `HttpClient` instance to be reused for scenarios where different `User-Agent` headers are required. - `Expect100Continue` Another option is to use a simple HTTP client factory as described [above](#simple-factory). diff --git a/src/RestSharp/RestClient.cs b/src/RestSharp/RestClient.cs index d4ae91867..ccaae9f21 100644 --- a/src/RestSharp/RestClient.cs +++ b/src/RestSharp/RestClient.cs @@ -73,6 +73,7 @@ public RestClient( ConfigureSerializers(configureSerialization); Options = new ReadOnlyRestClientOptions(options); + DefaultParameters = new DefaultParameters(Options); if (useClientFactory) { _disposeHttpClient = false; @@ -83,8 +84,6 @@ public RestClient( HttpClient = GetClient(); } - DefaultParameters = new DefaultParameters(Options); - HttpClient GetClient() { var handler = new HttpClientHandler(); ConfigureHttpMessageHandler(handler, Options); @@ -92,6 +91,7 @@ HttpClient GetClient() { var httpClient = new HttpClient(finalHandler); ConfigureHttpClient(httpClient, options); + ConfigureDefaultParameters(options); configureDefaultHeaders?.Invoke(httpClient.DefaultRequestHeaders); return httpClient; } @@ -181,7 +181,10 @@ public RestClient( Options = new ReadOnlyRestClientOptions(opt); DefaultParameters = new DefaultParameters(Options); - if (options != null) ConfigureHttpClient(httpClient, options); + if (options != null) { + ConfigureHttpClient(httpClient, options); + ConfigureDefaultParameters(options); + } } /// @@ -218,11 +221,6 @@ public RestClient( static void ConfigureHttpClient(HttpClient httpClient, RestClientOptions options) { if (options.MaxTimeout > 0) httpClient.Timeout = TimeSpan.FromMilliseconds(options.MaxTimeout); - if (options.UserAgent != null && - httpClient.DefaultRequestHeaders.UserAgent.All(x => $"{x.Product?.Name}/{x.Product?.Version}" != options.UserAgent)) { - httpClient.DefaultRequestHeaders.TryAddWithoutValidation(KnownHeaders.UserAgent, options.UserAgent); - } - if (options.Expect100Continue != null) httpClient.DefaultRequestHeaders.ExpectContinue = options.Expect100Continue; } @@ -270,6 +268,15 @@ void ConfigureSerializers(ConfigureSerialization? configureSerialization) { AcceptedContentTypes = Serializers.GetAcceptedContentTypes(); } + void ConfigureDefaultParameters(RestClientOptions options) { + if (options.UserAgent != null) { + if (!options.AllowMultipleDefaultParametersWithSameName + && DefaultParameters.Any(parameter => parameter.Type == ParameterType.HttpHeader && parameter.Name == KnownHeaders.UserAgent)) + DefaultParameters.RemoveParameter(KnownHeaders.UserAgent, ParameterType.HttpHeader); + DefaultParameters.AddParameter(Parameter.CreateParameter(KnownHeaders.UserAgent, options.UserAgent, ParameterType.HttpHeader)); + } + } + readonly bool _disposeHttpClient; bool _disposed; diff --git a/test/RestSharp.Tests/RestClientTests.cs b/test/RestSharp.Tests/RestClientTests.cs index 276f1e92a..0bd5dd073 100644 --- a/test/RestSharp.Tests/RestClientTests.cs +++ b/test/RestSharp.Tests/RestClientTests.cs @@ -118,20 +118,41 @@ public void Should_use_new_httpClient_instance() { } [Fact] - public void ConfigureHttpClient_does_not_duplicate_user_agent_for_same_client() { + public void ConfigureDefaultParameters_sets_user_agent_new_httpClient_instance() { + // arrange + var clientOptions = new RestClientOptions(); + + // act + var restClient = new RestClient(clientOptions); + + //assert + Assert.Single( + restClient.DefaultParameters, + parameter => parameter.Type == ParameterType.HttpHeader && + parameter.Name == KnownHeaders.UserAgent && + parameter.Value is string valueAsString && + valueAsString == clientOptions.UserAgent); + + Assert.Empty(restClient.HttpClient.DefaultRequestHeaders.UserAgent); + } + + [Fact] + public void ConfigureDefaultParameters_sets_user_agent_given_httpClient_instance() { // arrange var httpClient = new HttpClient(); var clientOptions = new RestClientOptions(); // act - var unused = new RestClient(httpClient, clientOptions); - var dummy = new RestClient(httpClient, clientOptions); + var restClient = new RestClient(httpClient, clientOptions); - // assert - Assert.Contains( - httpClient.DefaultRequestHeaders.UserAgent, - agent => $"{agent.Product.Name}/{agent.Product.Version}" == clientOptions.UserAgent - ); - Assert.Single(httpClient.DefaultRequestHeaders.UserAgent); + //assert + Assert.Single( + restClient.DefaultParameters, + parameter => parameter.Type == ParameterType.HttpHeader && + parameter.Name == KnownHeaders.UserAgent && + parameter.Value is string valueAsString && + valueAsString == clientOptions.UserAgent); + + Assert.Empty(httpClient.DefaultRequestHeaders.UserAgent); } }