Skip to content

Commit df05ab9

Browse files
committed
Default headers should allow multiple values
1 parent b82834b commit df05ab9

File tree

7 files changed

+44
-24
lines changed

7 files changed

+44
-24
lines changed

gen/SourceGenerator/ImmutableGenerator.cs

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,22 +32,24 @@ public void Execute(GeneratorExecutionContext context) {
3232

3333
static string GenerateImmutableClass(TypeDeclarationSyntax mutableClass, Compilation compilation) {
3434
var containingNamespace = compilation.GetSemanticModel(mutableClass.SyntaxTree).GetDeclaredSymbol(mutableClass)!.ContainingNamespace;
35-
36-
var namespaceName = containingNamespace.ToDisplayString();
37-
38-
var className = mutableClass.Identifier.Text;
39-
40-
var usings = mutableClass.SyntaxTree.GetCompilationUnitRoot().Usings.Select(u => u.ToString());
35+
var namespaceName = containingNamespace.ToDisplayString();
36+
var className = mutableClass.Identifier.Text;
37+
var usings = mutableClass.SyntaxTree.GetCompilationUnitRoot().Usings.Select(u => u.ToString());
4138

4239
var properties = GetDefinitions(SyntaxKind.SetKeyword)
43-
.Select(prop => $" public {prop.Type} {prop.Identifier.Text} {{ get; }}")
40+
.Select(
41+
prop => {
42+
var xml = prop.GetLeadingTrivia().FirstOrDefault(x => x.IsKind(SyntaxKind.SingleLineDocumentationCommentTrivia)).GetStructure();
43+
return $"/// {xml} public {prop.Type} {prop.Identifier.Text} {{ get; }}";
44+
}
45+
)
4446
.ToArray();
4547

4648
var props = GetDefinitions(SyntaxKind.SetKeyword).ToArray();
4749

4850
const string argName = "inner";
49-
var mutableProperties = props
50-
.Select(prop => $" {prop.Identifier.Text} = {argName}.{prop.Identifier.Text};");
51+
52+
var mutableProperties = props.Select(prop => $" {prop.Identifier.Text} = {argName}.{prop.Identifier.Text};");
5153

5254
var constructor = $$"""
5355
public ReadOnly{{className}}({{className}} {{argName}}) {
@@ -85,7 +87,8 @@ IEnumerable<PropertyDeclarationSyntax> GetDefinitions(SyntaxKind kind)
8587
.OfType<PropertyDeclarationSyntax>()
8688
.Where(
8789
prop =>
88-
prop.AccessorList!.Accessors.Any(accessor => accessor.Keyword.IsKind(kind)) && prop.AttributeLists.All(list => list.Attributes.All(attr => attr.Name.ToString() != "Exclude"))
90+
prop.AccessorList!.Accessors.Any(accessor => accessor.Keyword.IsKind(kind)) &&
91+
prop.AttributeLists.All(list => list.Attributes.All(attr => attr.Name.ToString() != "Exclude"))
8992
);
9093
}
91-
}
94+
}

src/RestSharp/Options/RestClientOptions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ public RestClientOptions(string baseUrl) : this(new Uri(Ensure.NotEmptyString(ba
210210

211211
/// <summary>
212212
/// Set to true to allow multiple default parameters with the same name. Default is false.
213+
/// This setting doesn't apply to headers as multiple header values for the same key is allowed.
213214
/// </summary>
214215
public bool AllowMultipleDefaultParametersWithSameName { get; set; }
215216

src/RestSharp/Parameters/DefaultParameters.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,7 @@ public sealed class DefaultParameters(ReadOnlyRestClientOptions options) : Param
2828
[MethodImpl(MethodImplOptions.Synchronized)]
2929
public DefaultParameters AddParameter(Parameter parameter) {
3030
if (parameter.Type == ParameterType.RequestBody)
31-
throw new NotSupportedException(
32-
"Cannot set request body using default parameters. Use Request.AddBody() instead."
33-
);
31+
throw new NotSupportedException("Cannot set request body using default parameters. Use Request.AddBody() instead.");
3432

3533
if (!options.AllowMultipleDefaultParametersWithSameName &&
3634
parameter.Type != ParameterType.HttpHeader &&

src/RestSharp/Parameters/Parameter.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,16 @@ protected Parameter(string? name, object? value, ParameterType type, bool encode
4444
/// Return a human-readable representation of this parameter
4545
/// </summary>
4646
/// <returns>String</returns>
47-
public sealed override string ToString() => Value == null ? $"{Name}" : $"{Name}={Value}";
47+
public sealed override string ToString() => Value == null ? $"{Name}" : $"{Name}={ValueString}";
48+
49+
protected virtual string ValueString => Value?.ToString() ?? "null";
4850

4951
public static Parameter CreateParameter(string? name, object? value, ParameterType type, bool encode = true)
5052
// ReSharper disable once SwitchExpressionHandlesSomeKnownEnumValuesWithExceptionInDefault
5153
=> type switch {
5254
ParameterType.GetOrPost => new GetOrPostParameter(Ensure.NotEmptyString(name, nameof(name)), value?.ToString(), encode),
5355
ParameterType.UrlSegment => new UrlSegmentParameter(Ensure.NotEmptyString(name, nameof(name)), value?.ToString()!, encode),
54-
ParameterType.HttpHeader => new HeaderParameter(name, value?.ToString()),
56+
ParameterType.HttpHeader => new HeaderParameter(name!, value?.ToString()!),
5557
ParameterType.QueryString => new QueryParameter(Ensure.NotEmptyString(name, nameof(name)), value?.ToString(), encode),
5658
_ => throw new ArgumentOutOfRangeException(nameof(type), type, null)
5759
};

src/RestSharp/Request/RestRequest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
using RestSharp.Authenticators;
1717
using RestSharp.Extensions;
1818
using RestSharp.Interceptors;
19-
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
2019

20+
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
2121
// ReSharper disable UnusedAutoPropertyAccessor.Global
2222

2323
namespace RestSharp;

src/RestSharp/Request/RestRequestExtensions.Headers.cs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,21 @@
1717
namespace RestSharp;
1818

1919
public static partial class RestRequestExtensions {
20+
/// <summary>
21+
/// Adds a header to the request. RestSharp will try to separate request and content headers when calling the resource.
22+
/// </summary>
23+
/// <param name="request">Request instance</param>
24+
/// <param name="name">Header name</param>
25+
/// <param name="values">Header values</param>
26+
/// <returns></returns>
27+
public static RestRequest AddHeader(this RestRequest request, string name, string[] values) {
28+
foreach (var value in values) {
29+
AddHeader(request, name, value);
30+
}
31+
32+
return request;
33+
}
34+
2035
/// <summary>
2136
/// Adds a header to the request. RestSharp will try to separate request and content headers when calling the resource.
2237
/// </summary>
@@ -41,7 +56,7 @@ public static RestRequest AddHeader<T>(this RestRequest request, string name, T
4156

4257
/// <summary>
4358
/// Adds or updates the request header. RestSharp will try to separate request and content headers when calling the resource.
44-
/// Existing header with the same name will be replaced.
59+
/// The existing header with the same name will be replaced.
4560
/// </summary>
4661
/// <param name="request">Request instance</param>
4762
/// <param name="name">Header name</param>
@@ -54,7 +69,7 @@ public static RestRequest AddOrUpdateHeader(this RestRequest request, string nam
5469

5570
/// <summary>
5671
/// Adds or updates the request header. RestSharp will try to separate request and content headers when calling the resource.
57-
/// Existing header with the same name will be replaced.
72+
/// The existing header with the same name will be replaced.
5873
/// </summary>
5974
/// <param name="request">Request instance</param>
6075
/// <param name="name">Header name</param>

test/RestSharp.Tests/RequestHeaderTests.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ public void AddOrUpdateHeader_ShouldUpdateExistingHeader_WhenHeaderExist() {
6363
request.AddOrUpdateHeader(KnownHeaders.Accept, ContentType.Json);
6464

6565
// Assert
66-
var headers = GetHeaders(request);
6766
GetHeader(request, KnownHeaders.Accept).Should().Be(ContentType.Json);
6867
}
6968

@@ -158,16 +157,18 @@ public void AddOrUpdateHeaders_ShouldAddAndUpdateHeaders_WhenSomeExists() {
158157

159158
[Fact]
160159
public void Should_not_allow_null_header_value() {
161-
var request = new RestRequest();
162-
Assert.Throws<ArgumentNullException>("value", () => request.AddHeader("name", null!));
160+
string value = null;
161+
var request = new RestRequest();
162+
// ReSharper disable once AssignNullToNotNullAttribute
163+
Assert.Throws<ArgumentNullException>("value", () => request.AddHeader("name", value));
163164
}
164-
165+
165166
[Fact]
166167
public void Should_not_allow_null_header_name() {
167168
var request = new RestRequest();
168169
Assert.Throws<ArgumentNullException>("name", () => request.AddHeader(null!, "value"));
169170
}
170-
171+
171172
[Fact]
172173
public void Should_not_allow_empty_header_name() {
173174
var request = new RestRequest();

0 commit comments

Comments
 (0)