diff --git a/src/RestSharp/Request/RequestContent.cs b/src/RestSharp/Request/RequestContent.cs index bf900be82..7064b5854 100644 --- a/src/RestSharp/Request/RequestContent.cs +++ b/src/RestSharp/Request/RequestContent.cs @@ -23,20 +23,22 @@ namespace RestSharp; class RequestContent : IDisposable { - readonly RestClient _client; - readonly RestRequest _request; - readonly List _streams = new(); + readonly RestClient _client; + readonly RestRequest _request; + readonly List _streams = new(); + readonly ParametersCollection _parameters; HttpContent? Content { get; set; } public RequestContent(RestClient client, RestRequest request) { - _client = client; - _request = request; + _client = client; + _request = request; + _parameters = new ParametersCollection(_request.Parameters.Union(_client.DefaultParameters)); } public HttpContent BuildContent() { AddFiles(); - var postParameters = _request.Parameters.GetContentParameters(_request.Method).ToArray(); + var postParameters = _parameters.GetContentParameters(_request.Method).ToArray(); AddBody(postParameters.Length > 0); AddPostParameters(postParameters); AddHeaders(); @@ -170,7 +172,7 @@ void AddPostParameters(GetOrPostParameter[] postParameters) { #else // However due to bugs in HttpClient FormUrlEncodedContent (see https://github.com/restsharp/RestSharp/issues/1814) we // do the encoding ourselves using WebUtility.UrlEncode instead. - var encodedItems = postParameters.Select(x => $"{x.Name!.UrlEncode()}={x.Value?.ToString()?.UrlEncode() ?? string.Empty}"); + var encodedItems = postParameters.Select(x => $"{x.Name!.UrlEncode()}={x.Value?.ToString()?.UrlEncode() ?? string.Empty}"); var encodedContent = new StringContent(encodedItems.JoinToString("&"), null, ContentType.FormUrlEncoded.Value); Content = encodedContent; #endif @@ -178,7 +180,7 @@ void AddPostParameters(GetOrPostParameter[] postParameters) { } void AddHeaders() { - var contentHeaders = _request.Parameters + var contentHeaders = _parameters .GetParameters() .Where(x => IsContentHeader(x.Name!)) .ToArray(); diff --git a/test/RestSharp.Tests.Integrated/HttpHeadersTests.cs b/test/RestSharp.Tests.Integrated/HttpHeadersTests.cs index 0e19c5d38..d5714eadd 100644 --- a/test/RestSharp.Tests.Integrated/HttpHeadersTests.cs +++ b/test/RestSharp.Tests.Integrated/HttpHeadersTests.cs @@ -1,24 +1,26 @@ +using System.Net; using RestSharp.Tests.Integrated.Fixtures; +using RestSharp.Tests.Integrated.Server; using RestSharp.Tests.Shared.Fixtures; namespace RestSharp.Tests.Integrated; -public class HttpHeadersTests : CaptureFixture { +[Collection(nameof(TestServerCollection))] +public class HttpHeadersTests { readonly ITestOutputHelper _output; + readonly RestClient _client; - public HttpHeadersTests(ITestOutputHelper output) => _output = output; + public HttpHeadersTests(TestServerFixture fixture, ITestOutputHelper output) { + _output = output; + _client = new RestClient(new RestClientOptions(fixture.Server.Url) { ThrowOnAnyError = true }); + } [Fact] public async Task Ensure_headers_correctly_set_in_the_hook() { const string headerName = "HeaderName"; const string headerValue = "HeaderValue"; - using var server = SimpleServer.Create(Handlers.Generic()); - - // Prepare - var client = new RestClient(server.Url); - - var request = new RestRequest(RequestHeadCapturer.Resource) { + var request = new RestRequest("/headers") { OnBeforeRequest = http => { http.Headers.Add(headerName, headerValue); return default; @@ -26,9 +28,35 @@ public async Task Ensure_headers_correctly_set_in_the_hook() { }; // Run - await client.ExecuteAsync(request); + var response = await _client.ExecuteAsync(request); // Assert - RequestHeadCapturer.CapturedHeaders[headerName].Should().Be(headerValue); + response.StatusCode.Should().Be(HttpStatusCode.OK); + var header = response.Data!.First(x => x.Name == headerName); + header.Should().NotBeNull(); + header.Value.Should().Be(headerValue); } + + [Fact] + public async Task Should_use_both_default_and_request_headers() { + var defaultHeader = new Header("defName", "defValue"); + var requestHeader = new Header("reqName", "reqValue"); + + _client.AddDefaultHeader(defaultHeader.Name, defaultHeader.Value); + + var request = new RestRequest("/headers") + .AddHeader(requestHeader.Name, requestHeader.Value); + + var response = await _client.ExecuteAsync(request); + CheckHeader(defaultHeader); + CheckHeader(requestHeader); + + void CheckHeader(Header header) { + var h = response.Data!.First(x => x.Name == header.Name); + h.Should().NotBeNull(); + h.Value.Should().Be(header.Value); + } + } + + record Header(string Name, string Value); } \ No newline at end of file diff --git a/test/RestSharp.Tests.Integrated/PostTests.cs b/test/RestSharp.Tests.Integrated/PostTests.cs index a37a454a6..4319aa06b 100644 --- a/test/RestSharp.Tests.Integrated/PostTests.cs +++ b/test/RestSharp.Tests.Integrated/PostTests.cs @@ -47,7 +47,32 @@ public async Task Should_post_large_form_data() { response.Data!.Message.Should().Be($"Works! Length: {length}"); } + [Fact] + public async Task Should_post_both_default_and_request_parameters() { + var defParam = new PostParameter("default", "default"); + var reqParam = new PostParameter("request", "request"); + + _client.AddDefaultParameter(defParam.Name, defParam.Value); + + var request = new RestRequest("post/data") + .AddParameter(reqParam.Name, reqParam.Value); + + var response = await _client.ExecutePostAsync(request); + response.StatusCode.Should().Be(HttpStatusCode.OK); + + CheckResponse(defParam); + CheckResponse(reqParam); + + void CheckResponse(PostParameter parameter) { + var p = response.Data!.FirstOrDefault(x => x.Name == parameter.Name); + p.Should().NotBeNull(); + p.Value.Should().Be(parameter.Value); + } + } + class Response { public string Message { get; set; } } + + record PostParameter(string Name, string Value); } diff --git a/test/RestSharp.Tests.Integrated/RequestHeadTests.cs b/test/RestSharp.Tests.Integrated/RequestHeadTests.cs index a69cc5b9b..1c5d98eb1 100644 --- a/test/RestSharp.Tests.Integrated/RequestHeadTests.cs +++ b/test/RestSharp.Tests.Integrated/RequestHeadTests.cs @@ -54,7 +54,7 @@ public async Task Passes_Default_Credentials_When_UseDefaultCredentials_Is_True( response.StatusCode.ToString().Should().BeOneOf(HttpStatusCode.OK.ToString(),HttpStatusCode.Unauthorized.ToString()); RequestHeadCapturer.CapturedHeaders.Should().NotBeNull(); - var keys = RequestHeadCapturer.CapturedHeaders.Keys.Cast().ToArray(); + var keys = RequestHeadCapturer.CapturedHeaders!.Keys.Cast().ToArray(); keys.Should() .Contain( diff --git a/test/RestSharp.Tests.Integrated/Server/Handlers/FormRequest.cs b/test/RestSharp.Tests.Integrated/Server/Handlers/FormRequest.cs new file mode 100644 index 000000000..a4ab7f90c --- /dev/null +++ b/test/RestSharp.Tests.Integrated/Server/Handlers/FormRequest.cs @@ -0,0 +1,12 @@ +using Microsoft.AspNetCore.Http; + +namespace RestSharp.Tests.Integrated.Server.Handlers; + +public static class FormRequestHandler { + public static IResult HandleForm(HttpContext ctx) { + var response = ctx.Request.Form.Select( + x => new TestServerResponse(x.Key, x.Value) + ); + return Results.Ok(response); + } +} diff --git a/test/RestSharp.Tests.Integrated/Server/TestServer.cs b/test/RestSharp.Tests.Integrated/Server/TestServer.cs index df9307e07..4eed43032 100644 --- a/test/RestSharp.Tests.Integrated/Server/TestServer.cs +++ b/test/RestSharp.Tests.Integrated/Server/TestServer.cs @@ -61,6 +61,8 @@ public HttpServer(ITestOutputHelper? output = null) { "/post/form", (HttpContext context) => new TestResponse { Message = $"Works! Length: {context.Request.Form["big_string"].ToString().Length}" } ); + + _app.MapPost("/post/data", FormRequestHandler.HandleForm); } public Uri Url => new(Address); diff --git a/test/RestSharp.Tests.Serializers.Xml/SampleClasses/twitter.cs b/test/RestSharp.Tests.Serializers.Xml/SampleClasses/twitter.cs index 53cdb83b1..d09df6540 100644 --- a/test/RestSharp.Tests.Serializers.Xml/SampleClasses/twitter.cs +++ b/test/RestSharp.Tests.Serializers.Xml/SampleClasses/twitter.cs @@ -1,8 +1,11 @@ using RestSharp.Serializers; +// ReSharper disable InconsistentNaming namespace RestSharp.Tests.Serializers.Xml.SampleClasses; +#pragma warning disable CS8981 public class status { +#pragma warning restore CS8981 public bool truncated { get; set; } public string created_at { get; set; }