Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions src/Http/Wolverine.Http.Tests/using_form_parameters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -536,4 +536,22 @@ public void trouble_shoot_form_matching()
var variable = chain.TryFindOrCreateFormValue(parameter);
variable!.Creator.ShouldBeOfType<ParsedArrayFormValue>();
}

[Fact]
public void form_endpoints_honor_consumes_metadata_for_supported_request_formats()
{
// fillRequestType only seeds SupportedRequestFormats from
// IAcceptsMetadata when the endpoint has a body request type and is
// not a form endpoint. Form endpoints used to fall through and rely
// on ASP.NET Core OpenAPI's "application/x-www-form-urlencoded"
// default, which silently dropped [Consumes("multipart/form-data")]
// and caused generated clients (Orval, NSwag) to emit URLSearchParams
// bodies instead of multipart for file-upload endpoints.
var chain = HttpChains.ChainFor("POST", "/form/multipart-consumes");
var apiDescription = chain!.CreateApiDescription("POST");

apiDescription.SupportedRequestFormats
.Select(f => f.MediaType)
.ShouldContain("multipart/form-data");
}
}
23 changes: 23 additions & 0 deletions src/Http/Wolverine.Http/HttpChain.ApiDescription.cs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,29 @@ public ApiDescription CreateApiDescription(string httpMethod)
apiDescription.ParameterDescriptions.Add(parameterDescription);
}

// fillRequestType only honors [Consumes] / IAcceptsMetadata for body
// endpoints (HasRequestType && !IsFormData). Without this, form
// endpoints fall through and ASP.NET Core OpenAPI's GetFormRequestBody
// defaults SupportedRequestFormats to "application/x-www-form-urlencoded"
// — silently dropping [Consumes("multipart/form-data")] on file-upload
// endpoints and causing client generators (Orval, NSwag, Kiota) to emit
// URLSearchParams bodies instead of multipart.
if (apiDescription.SupportedRequestFormats.Count == 0 &&
apiDescription.ParameterDescriptions.Any(p =>
p.Source == BindingSource.Form || p.Source == BindingSource.FormFile))
{
foreach (var metadata in Endpoint!.Metadata.OfType<IAcceptsMetadata>())
{
foreach (var contentType in metadata.ContentTypes)
{
apiDescription.SupportedRequestFormats.Add(new ApiRequestFormat
{
MediaType = contentType
});
}
}
}

return apiDescription;
}

Expand Down
4 changes: 4 additions & 0 deletions src/Http/WolverineWebApi/Forms/FormEndpoints.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ public static string PostWithFiles([FromForm] FormWithFiles form)
{
return $"{form.Name}|{form.Files?.Count}";
}

[WolverinePost("/form/multipart-consumes")]
[Consumes("multipart/form-data")]
public static string MultipartConsumes([FromForm] string value) => value ?? "";
}

public class FormWithFile
Expand Down
Loading