Skip to content

Commit

Permalink
.Net: Handle media types with parameters (#10000)
Browse files Browse the repository at this point in the history
### Motivation, Context and Description
This PR updates the RestApiOperationRunner class to be resilient to
media types specified with parameters. It's a continuation of the first
PR - #9959, where the
OpenApiDocumentParser was updated to allow media types with parameters.
  • Loading branch information
SergeyMenshykh authored Jan 6, 2025
1 parent 2cc5830 commit caf416f
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,15 @@ private async Task<RestApiOperationResponse> ReadContentAndCreateOperationRespon
mediaType = mediaTypeFallback;
}

if (!this._payloadFactoryByMediaType.TryGetValue(mediaType!, out var payloadFactory))
// Remove media type parameters, such as x-api-version, from the "text/plain; x-api-version=2.0" media type string.
mediaType = mediaType!.Split(';').First();

// Normalize the media type to lowercase and remove trailing whitespaces.
#pragma warning disable CA1308 // Normalize strings to uppercase
mediaType = mediaType!.ToLowerInvariant().Trim();
#pragma warning restore CA1308 // Normalize strings to uppercase

if (!this._payloadFactoryByMediaType.TryGetValue(mediaType, out var payloadFactory))
{
throw new KernelException($"The media type {mediaType} of the {operation.Id} operation is not supported by {nameof(RestApiOperationRunner)}.");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1705,6 +1705,44 @@ public async Task ItShouldReturnExpectedSchemaAsync(string expectedStatusCode, p
Assert.Equal(JsonSerializer.Serialize(expected), JsonSerializer.Serialize(result.ExpectedSchema));
}

[Theory]
[InlineData("application/json;x-api-version=2.0", "application/json")]
[InlineData("application/json ; x-api-version=2.0", "application/json")]
[InlineData(" application/JSON; x-api-version=2.0", "application/json")]
[InlineData(" TEXT/PLAIN ; x-api-version=2.0", "text/plain")]
public async Task ItShouldNormalizeContentTypeArgumentAsync(string actualContentType, string normalizedContentType)
{
// Arrange
this._httpMessageHandlerStub.ResponseToReturn.Content = new StringContent("fake-content", Encoding.UTF8, MediaTypeNames.Text.Plain);

var operation = new RestApiOperation(
id: "fake-id",
servers: [new RestApiServer("https://fake-random-test-host")],
path: "fake-path",
method: HttpMethod.Post,
description: "fake-description",
parameters: [],
responses: new Dictionary<string, RestApiExpectedResponse>(),
securityRequirements: [],
payload: null
);

var arguments = new KernelArguments
{
{ "payload", "fake-input-value" },
{ "content-type", actualContentType },
};

var sut = new RestApiOperationRunner(this._httpClient, this._authenticationHandlerMock.Object, enableDynamicPayload: false);

// Act
var result = await sut.RunAsync(operation, arguments);

// Assert
Assert.NotNull(this._httpMessageHandlerStub.ContentHeaders);
Assert.Contains(this._httpMessageHandlerStub.ContentHeaders, h => h.Key == "Content-Type" && h.Value.Any(h => h.StartsWith(normalizedContentType, StringComparison.InvariantCulture)));
}

/// <summary>
/// Disposes resources used by this class.
/// </summary>
Expand Down

0 comments on commit caf416f

Please sign in to comment.