Я пытаюсь загрузить изображение без имени файла. API получил значение null в параметре файла.
Код отправки запроса (клиентская сторона):
var content = new MultipartFormDataContent
{
{ new StreamContent(file), "file" },
{ new StringContent(JsonConvert.SerializeObject(metadata), Encoding.UTF8, "application/json"), "metadata" }
};
Код получения запроса (API с .Net 8):
var form = await Request.ReadFormAsync();
var formFile = form.Files["file"];
//The formFile is returned as NULL
Если я укажу имя файла в содержимом потока, это сработает. Но мое требование - заставить его работать без указания имени файла.





Я нашел решение, нам нужно изменить код API следующим образом:
// Create a minimal API endpoint that handles a POST
// We use the default configured JsonOptions for deserializing the JSON
app.MapPost("/", async (HttpContext ctx, IOptions<JsonOptions> jsonOptions) =>
{
// make sure we have the correct header type
if (!MediaTypeHeaderValue.TryParse(ctx.Request.ContentType, out MediaTypeHeaderValue? contentType)
|| !contentType.MediaType.Equals("multipart/form-data", StringComparison.OrdinalIgnoreCase))
{
return Results.BadRequest("Incorrect mime-type");
}
// Variables for holding the data parsed from the response
MyData? jsonData = null;
byte[]? binaryData = null;
// Get the multipart/form-boundary header from the content-type
// Content-Type: multipart/form-data; boundary = "--73dc24e0-b350-48f8-931e-eab338df00e1"
// The spec says 70 characters is a reasonable limit.
string boundary = GetBoundary(contentType, lengthLimit: 70);
var multipartReader = new MultipartReader(boundary, ctx.Request.Body);
// Use the multipart reader to read each of the sections
while (await multipartReader.ReadNextSectionAsync(ct) is { } section)
{
// Make sure we have a content-type for the section
if (!MediaTypeHeaderValue.TryParse(section.ContentType, out MediaTypeHeaderValue? sectionType))
{
return Results.BadRequest("Invalid content type in section " + section.ContentType);
}
if (sectionType.MediaType.Equals("application/json", StringComparison.OrdinalIgnoreCase))
{
// If the section is JSON, deserialize directly from the section stream
// using the default JSON serialization options configured for the app
jsonData = await JsonSerializer.DeserializeAsync<MyData>(
section.Body,
jsonOptions.Value.JsonSerializerOptions,
cancellationToken: ctx.RequestAborted);
}
else if (sectionType.MediaType.Equals("application/octet-stream", StringComparison.OrdinalIgnoreCase))
{
// If the section is binary data, deserialize into an array
// there are potentially more efficient things we could do here
// depending on how you need the data
using var ms = new MemoryStream();
await section.Body.CopyToAsync(ms, ctx.RequestAborted);
binaryData = ms.ToArray();
}
else
{
return Results.BadRequest("Invalid content type in section " + section.ContentType);
}
}
// Just printing it out for debugging purposes
app.Logger.LogInformation("Receive Json {JsonData} and binary data {BinaryData}",
jsonData, Convert.ToBase64String(binaryData));
return Results.Ok();
// Retrieves the boundary marker from the content-type, handling quotes etc
// Taken from https://github.com/dotnet/aspnetcore/blob/4eef6a1578bb0d8a4469779798fe9390543d15c0/src/Http/Http/src/Features/FormFeature.cs#L318-L320
static string GetBoundary(MediaTypeHeaderValue contentType, int lengthLimit)
{
var boundary = HeaderUtilities.RemoveQuotes(contentType.Boundary);
if (StringSegment.IsNullOrEmpty(boundary))
{
throw new InvalidDataException("Missing content-type boundary.");
}
if (boundary.Length > lengthLimit)
{
throw new InvalidDataException($"Multipart boundary length limit {lengthLimit} exceeded.");
}
return boundary.ToString();
}
});
Источник кода: https://andrewlock.net/reading-json-and-binary-data-from-multipart-form-data-sections-in-aspnetcore/