Skip to content

Commit 5cffc45

Browse files
authored
C# GenericHost support multiple accept headers and allow access to HttpContentHeaders on response (#22232)
* Add support for other Accept header values or full arrays when multiple options are present. * Expose ContentHeaders on ApiResponse, to access ContentDisposition for example with file downloads. * Update samples and documentation * Fix build warning in samples
1 parent 6fc64e2 commit 5cffc45

196 files changed

Lines changed: 2652 additions & 1080 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

modules/openapi-generator/src/main/resources/csharp/libraries/generichost/ApiResponse`1.mustache

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ namespace {{packageName}}.{{clientPackage}}
4949
/// </summary>
5050
System.Net.Http.Headers.HttpResponseHeaders Headers { get; }
5151

52+
/// <summary>
53+
/// The headers contained in the api response related to the content
54+
/// </summary>
55+
System.Net.Http.Headers.HttpContentHeaders ContentHeaders { get; }
56+
5257
/// <summary>
5358
/// The path used when making the request.
5459
/// </summary>
@@ -106,6 +111,11 @@ namespace {{packageName}}.{{clientPackage}}
106111
/// </summary>
107112
public System.Net.Http.Headers.HttpResponseHeaders Headers { get; }
108113

114+
/// <summary>
115+
/// The headers contained in the api response related to the content
116+
/// </summary>
117+
public System.Net.Http.Headers.HttpContentHeaders ContentHeaders { get; }
118+
109119
/// <summary>
110120
/// The DateTime when the request was retrieved.
111121
/// </summary>
@@ -144,6 +154,7 @@ namespace {{packageName}}.{{clientPackage}}
144154
{
145155
StatusCode = httpResponseMessage.StatusCode;
146156
Headers = httpResponseMessage.Headers;
157+
ContentHeaders = httpResponseMessage.Content.Headers;
147158
IsSuccessStatusCode = httpResponseMessage.IsSuccessStatusCode;
148159
ReasonPhrase = httpResponseMessage.ReasonPhrase;
149160
RawContent = rawContent;
@@ -167,6 +178,7 @@ namespace {{packageName}}.{{clientPackage}}
167178
{
168179
StatusCode = httpResponseMessage.StatusCode;
169180
Headers = httpResponseMessage.Headers;
181+
ContentHeaders = httpResponseMessage.Content.Headers;
170182
IsSuccessStatusCode = httpResponseMessage.IsSuccessStatusCode;
171183
ReasonPhrase = httpResponseMessage.ReasonPhrase;
172184
ContentStream = contentStream;
@@ -178,6 +190,7 @@ namespace {{packageName}}.{{clientPackage}}
178190
OnCreated(httpRequestMessage, httpResponseMessage);
179191
}
180192

193+
181194
partial void OnCreated(global::System.Net.Http.HttpRequestMessage httpRequestMessage, System.Net.Http.HttpResponseMessage httpResponseMessage);
182195
}
183196
{{#x-http-statuses-with-return}}

modules/openapi-generator/src/main/resources/csharp/libraries/generichost/ClientUtils.mustache

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ using {{packageName}}.{{modelPackage}};
1818
{{/-first}}
1919
{{/models}}
2020
using System.Runtime.CompilerServices;
21+
using System.Net.Http.Headers;
2122

2223
{{>Assembly}}namespace {{packageName}}.{{clientPackage}}
2324
{
@@ -311,6 +312,36 @@ using System.Runtime.CompilerServices;
311312
return string.Join(",", accepts);
312313
}
313314

315+
316+
317+
/// <summary>
318+
/// Select the Accept header's value from the given accepts array:
319+
/// if JSON exists in the given array, use it;
320+
/// otherwise use all of them.
321+
/// </summary>
322+
/// <param name="accepts">The accepts array to select from.</param>
323+
/// <returns>The Accept header values to use.</returns>
324+
public static IEnumerable<MediaTypeWithQualityHeaderValue> SelectHeaderAcceptArray(string[] accepts)
325+
{
326+
if (accepts.Length == 0)
327+
{{#net80OrLater}}
328+
return [];
329+
{{/net80OrLater}}
330+
{{^net80OrLater}}
331+
return Enumerable.Empty<MediaTypeWithQualityHeaderValue>();
332+
{{/net80OrLater}}
333+
334+
if (accepts.Contains("application/json", StringComparer.OrdinalIgnoreCase))
335+
{{#net80OrLater}}
336+
return [MediaTypeWithQualityHeaderValue.Parse("application/json")];
337+
{{/net80OrLater}}
338+
{{^net80OrLater}}
339+
return new [] { MediaTypeWithQualityHeaderValue.Parse("application/json") };
340+
{{/net80OrLater}}
341+
342+
return accepts.Select(MediaTypeWithQualityHeaderValue.Parse);
343+
}
344+
314345
/// <summary>
315346
/// Provides a case-insensitive check that a provided content type is a known JSON-like content type.
316347
/// </summary>

modules/openapi-generator/src/main/resources/csharp/libraries/generichost/api.mustache

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
{{/nrt}}
99
using System;
1010
using System.Collections.Generic;
11+
using System.Collections.ObjectModel;
1112
{{#net80OrLater}}
1213
{{#lambda.uniqueLines}}
1314
{{#operations}}
@@ -20,6 +21,7 @@ using System.Linq;
2021
{{/lambda.uniqueLines}}
2122
{{/net80OrLater}}
2223
using System.Net;
24+
using System.IO;
2325
using System.Threading.Tasks;
2426
using Microsoft.Extensions.Logging;
2527
using System.Net.Http;
@@ -605,10 +607,10 @@ namespace {{packageName}}.{{apiPackage}}
605607
{{#produces}}
606608
{{#-first}}
607609

608-
string{{nrt?}} acceptLocalVar = ClientUtils.SelectHeaderAccept(acceptLocalVars);
610+
IEnumerable<MediaTypeWithQualityHeaderValue> acceptHeaderValuesLocalVar = ClientUtils.SelectHeaderAcceptArray(acceptLocalVars);
609611

610-
if (acceptLocalVar != null)
611-
httpRequestMessageLocalVar.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(acceptLocalVar));
612+
foreach (var acceptLocalVar in acceptHeaderValuesLocalVar)
613+
httpRequestMessageLocalVar.Headers.Accept.Add(acceptLocalVar);
612614
{{/-first}}
613615
{{/produces}}
614616
{{#net60OrLater}}

samples/client/petstore/csharp/generichost/latest/ComposedEnum/src/Org.OpenAPITools/Client/ApiResponse`1.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ public partial interface IApiResponse
5252
/// </summary>
5353
System.Net.Http.Headers.HttpResponseHeaders Headers { get; }
5454

55+
/// <summary>
56+
/// The headers contained in the api response related to the content
57+
/// </summary>
58+
System.Net.Http.Headers.HttpContentHeaders ContentHeaders { get; }
59+
5560
/// <summary>
5661
/// The path used when making the request.
5762
/// </summary>
@@ -109,6 +114,11 @@ public partial class ApiResponse : IApiResponse
109114
/// </summary>
110115
public System.Net.Http.Headers.HttpResponseHeaders Headers { get; }
111116

117+
/// <summary>
118+
/// The headers contained in the api response related to the content
119+
/// </summary>
120+
public System.Net.Http.Headers.HttpContentHeaders ContentHeaders { get; }
121+
112122
/// <summary>
113123
/// The DateTime when the request was retrieved.
114124
/// </summary>
@@ -147,6 +157,7 @@ public ApiResponse(global::System.Net.Http.HttpRequestMessage httpRequestMessage
147157
{
148158
StatusCode = httpResponseMessage.StatusCode;
149159
Headers = httpResponseMessage.Headers;
160+
ContentHeaders = httpResponseMessage.Content.Headers;
150161
IsSuccessStatusCode = httpResponseMessage.IsSuccessStatusCode;
151162
ReasonPhrase = httpResponseMessage.ReasonPhrase;
152163
RawContent = rawContent;
@@ -170,6 +181,7 @@ public ApiResponse(global::System.Net.Http.HttpRequestMessage httpRequestMessage
170181
{
171182
StatusCode = httpResponseMessage.StatusCode;
172183
Headers = httpResponseMessage.Headers;
184+
ContentHeaders = httpResponseMessage.Content.Headers;
173185
IsSuccessStatusCode = httpResponseMessage.IsSuccessStatusCode;
174186
ReasonPhrase = httpResponseMessage.ReasonPhrase;
175187
ContentStream = contentStream;
@@ -181,6 +193,7 @@ public ApiResponse(global::System.Net.Http.HttpRequestMessage httpRequestMessage
181193
OnCreated(httpRequestMessage, httpResponseMessage);
182194
}
183195

196+
184197
partial void OnCreated(global::System.Net.Http.HttpRequestMessage httpRequestMessage, System.Net.Http.HttpResponseMessage httpResponseMessage);
185198
}
186199
}

samples/client/petstore/csharp/generichost/latest/ComposedEnum/src/Org.OpenAPITools/Client/ClientUtils.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
using System.Text.RegularExpressions;
2020
using Org.OpenAPITools.Model;
2121
using System.Runtime.CompilerServices;
22+
using System.Net.Http.Headers;
2223

2324
[assembly: InternalsVisibleTo("Org.OpenAPITools.Test")]
2425

@@ -226,6 +227,26 @@ public static byte[] ReadAsBytes(Stream inputStream)
226227
return string.Join(",", accepts);
227228
}
228229

230+
231+
232+
/// <summary>
233+
/// Select the Accept header's value from the given accepts array:
234+
/// if JSON exists in the given array, use it;
235+
/// otherwise use all of them.
236+
/// </summary>
237+
/// <param name="accepts">The accepts array to select from.</param>
238+
/// <returns>The Accept header values to use.</returns>
239+
public static IEnumerable<MediaTypeWithQualityHeaderValue> SelectHeaderAcceptArray(string[] accepts)
240+
{
241+
if (accepts.Length == 0)
242+
return [];
243+
244+
if (accepts.Contains("application/json", StringComparer.OrdinalIgnoreCase))
245+
return [MediaTypeWithQualityHeaderValue.Parse("application/json")];
246+
247+
return accepts.Select(MediaTypeWithQualityHeaderValue.Parse);
248+
}
249+
229250
/// <summary>
230251
/// Provides a case-insensitive check that a provided content type is a known JSON-like content type.
231252
/// </summary>

samples/client/petstore/csharp/generichost/latest/HelloWorld/src/Org.OpenAPITools/Api/DefaultApi.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@
1212

1313
using System;
1414
using System.Collections.Generic;
15+
using System.Collections.ObjectModel;
1516
using System.Net;
17+
using System.IO;
1618
using System.Threading.Tasks;
1719
using Microsoft.Extensions.Logging;
1820
using System.Net.Http;

samples/client/petstore/csharp/generichost/latest/HelloWorld/src/Org.OpenAPITools/Client/ApiResponse`1.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ public partial interface IApiResponse
5252
/// </summary>
5353
System.Net.Http.Headers.HttpResponseHeaders Headers { get; }
5454

55+
/// <summary>
56+
/// The headers contained in the api response related to the content
57+
/// </summary>
58+
System.Net.Http.Headers.HttpContentHeaders ContentHeaders { get; }
59+
5560
/// <summary>
5661
/// The path used when making the request.
5762
/// </summary>
@@ -109,6 +114,11 @@ public partial class ApiResponse : IApiResponse
109114
/// </summary>
110115
public System.Net.Http.Headers.HttpResponseHeaders Headers { get; }
111116

117+
/// <summary>
118+
/// The headers contained in the api response related to the content
119+
/// </summary>
120+
public System.Net.Http.Headers.HttpContentHeaders ContentHeaders { get; }
121+
112122
/// <summary>
113123
/// The DateTime when the request was retrieved.
114124
/// </summary>
@@ -147,6 +157,7 @@ public ApiResponse(global::System.Net.Http.HttpRequestMessage httpRequestMessage
147157
{
148158
StatusCode = httpResponseMessage.StatusCode;
149159
Headers = httpResponseMessage.Headers;
160+
ContentHeaders = httpResponseMessage.Content.Headers;
150161
IsSuccessStatusCode = httpResponseMessage.IsSuccessStatusCode;
151162
ReasonPhrase = httpResponseMessage.ReasonPhrase;
152163
RawContent = rawContent;
@@ -170,6 +181,7 @@ public ApiResponse(global::System.Net.Http.HttpRequestMessage httpRequestMessage
170181
{
171182
StatusCode = httpResponseMessage.StatusCode;
172183
Headers = httpResponseMessage.Headers;
184+
ContentHeaders = httpResponseMessage.Content.Headers;
173185
IsSuccessStatusCode = httpResponseMessage.IsSuccessStatusCode;
174186
ReasonPhrase = httpResponseMessage.ReasonPhrase;
175187
ContentStream = contentStream;
@@ -181,6 +193,7 @@ public ApiResponse(global::System.Net.Http.HttpRequestMessage httpRequestMessage
181193
OnCreated(httpRequestMessage, httpResponseMessage);
182194
}
183195

196+
184197
partial void OnCreated(global::System.Net.Http.HttpRequestMessage httpRequestMessage, System.Net.Http.HttpResponseMessage httpResponseMessage);
185198
}
186199
}

samples/client/petstore/csharp/generichost/latest/HelloWorld/src/Org.OpenAPITools/Client/ClientUtils.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
using System.Text.RegularExpressions;
2020
using Org.OpenAPITools.Model;
2121
using System.Runtime.CompilerServices;
22+
using System.Net.Http.Headers;
2223

2324
[assembly: InternalsVisibleTo("Org.OpenAPITools.Test")]
2425

@@ -220,6 +221,26 @@ public static byte[] ReadAsBytes(Stream inputStream)
220221
return string.Join(",", accepts);
221222
}
222223

224+
225+
226+
/// <summary>
227+
/// Select the Accept header's value from the given accepts array:
228+
/// if JSON exists in the given array, use it;
229+
/// otherwise use all of them.
230+
/// </summary>
231+
/// <param name="accepts">The accepts array to select from.</param>
232+
/// <returns>The Accept header values to use.</returns>
233+
public static IEnumerable<MediaTypeWithQualityHeaderValue> SelectHeaderAcceptArray(string[] accepts)
234+
{
235+
if (accepts.Length == 0)
236+
return [];
237+
238+
if (accepts.Contains("application/json", StringComparer.OrdinalIgnoreCase))
239+
return [MediaTypeWithQualityHeaderValue.Parse("application/json")];
240+
241+
return accepts.Select(MediaTypeWithQualityHeaderValue.Parse);
242+
}
243+
223244
/// <summary>
224245
/// Provides a case-insensitive check that a provided content type is a known JSON-like content type.
225246
/// </summary>

samples/client/petstore/csharp/generichost/latest/InlineEnumAnyOf/src/Org.OpenAPITools/Api/DefaultApi.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@
1212

1313
using System;
1414
using System.Collections.Generic;
15+
using System.Collections.ObjectModel;
1516
using System.Net;
17+
using System.IO;
1618
using System.Threading.Tasks;
1719
using Microsoft.Extensions.Logging;
1820
using System.Net.Http;
@@ -253,10 +255,10 @@ public async Task<IIconsApiResponse> IconsAsync(Option<IconsSizeParameter> size
253255
"application/json"
254256
};
255257

256-
string? acceptLocalVar = ClientUtils.SelectHeaderAccept(acceptLocalVars);
258+
IEnumerable<MediaTypeWithQualityHeaderValue> acceptHeaderValuesLocalVar = ClientUtils.SelectHeaderAcceptArray(acceptLocalVars);
257259

258-
if (acceptLocalVar != null)
259-
httpRequestMessageLocalVar.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(acceptLocalVar));
260+
foreach (var acceptLocalVar in acceptHeaderValuesLocalVar)
261+
httpRequestMessageLocalVar.Headers.Accept.Add(acceptLocalVar);
260262

261263
httpRequestMessageLocalVar.Method = HttpMethod.Get;
262264

samples/client/petstore/csharp/generichost/latest/InlineEnumAnyOf/src/Org.OpenAPITools/Client/ApiResponse`1.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ public partial interface IApiResponse
5252
/// </summary>
5353
System.Net.Http.Headers.HttpResponseHeaders Headers { get; }
5454

55+
/// <summary>
56+
/// The headers contained in the api response related to the content
57+
/// </summary>
58+
System.Net.Http.Headers.HttpContentHeaders ContentHeaders { get; }
59+
5560
/// <summary>
5661
/// The path used when making the request.
5762
/// </summary>
@@ -109,6 +114,11 @@ public partial class ApiResponse : IApiResponse
109114
/// </summary>
110115
public System.Net.Http.Headers.HttpResponseHeaders Headers { get; }
111116

117+
/// <summary>
118+
/// The headers contained in the api response related to the content
119+
/// </summary>
120+
public System.Net.Http.Headers.HttpContentHeaders ContentHeaders { get; }
121+
112122
/// <summary>
113123
/// The DateTime when the request was retrieved.
114124
/// </summary>
@@ -147,6 +157,7 @@ public ApiResponse(global::System.Net.Http.HttpRequestMessage httpRequestMessage
147157
{
148158
StatusCode = httpResponseMessage.StatusCode;
149159
Headers = httpResponseMessage.Headers;
160+
ContentHeaders = httpResponseMessage.Content.Headers;
150161
IsSuccessStatusCode = httpResponseMessage.IsSuccessStatusCode;
151162
ReasonPhrase = httpResponseMessage.ReasonPhrase;
152163
RawContent = rawContent;
@@ -170,6 +181,7 @@ public ApiResponse(global::System.Net.Http.HttpRequestMessage httpRequestMessage
170181
{
171182
StatusCode = httpResponseMessage.StatusCode;
172183
Headers = httpResponseMessage.Headers;
184+
ContentHeaders = httpResponseMessage.Content.Headers;
173185
IsSuccessStatusCode = httpResponseMessage.IsSuccessStatusCode;
174186
ReasonPhrase = httpResponseMessage.ReasonPhrase;
175187
ContentStream = contentStream;
@@ -181,6 +193,7 @@ public ApiResponse(global::System.Net.Http.HttpRequestMessage httpRequestMessage
181193
OnCreated(httpRequestMessage, httpResponseMessage);
182194
}
183195

196+
184197
partial void OnCreated(global::System.Net.Http.HttpRequestMessage httpRequestMessage, System.Net.Http.HttpResponseMessage httpResponseMessage);
185198
}
186199

0 commit comments

Comments
 (0)