Как отправить HTTP-запрос POST с multipart/form-data с данными формы в первоначальном запросе в .NET Framework?C#

Место общения программистов C#
Ответить
Anonymous
 Как отправить HTTP-запрос POST с multipart/form-data с данными формы в первоначальном запросе в .NET Framework?

Сообщение Anonymous »

Мне нужно загрузить файл на встроенное устройство, на котором работает API.
Сначала я попытался написать методы для этого в тестовом проекте. Это прекрасно работает:

Код: Выделить всё

private static async Task POST_internal(string url, HttpContent payLoad)
{
var httpClient = new HttpClient();
httpClient.BaseAddress = new Uri(url);
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Add("Accept", "*/*");

try
{
var result = await httpClient.PostAsync(url, payLoad);

httpClient.Dispose();
return result;
}
catch (Exception)
{
httpClient.Dispose();
return null;
}
}
public static void POST_upload_token(IPAddress deviceIpAddress, string filename)
{
var requestURL = $"http://{deviceIpAddress}/api/upload_token";

using var payload = new MultipartFormDataContent();

payload.Add(new StreamContent(System.IO.File.OpenRead(filename)), "\"file\"", $"\"{Path.GetFileName(filename)}\"");

var response = POST_internal(requestURL, payload).Result;
if(response != null && response.IsSuccessStatusCode)
return;
throw new Exception($"Failed to post upload token to device.\nResponse code: {(response != null ? response.StatusCode : "Response was null")}\nResponse text {(response != null ? response.Content.ReadAsStringAsync().Result : "Response was null")}");
}
Однако при добавлении этого кода в основной проект он не работает. Либо API отвечает 400 Bad Request, либо вызов httpClient.PostAsync() выдает исключение (

Код: Выделить всё

Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
)
Единственное различие между тестовым проектом и основным проектом — это версии .NET. Тестовым проектом был .NET8, а основным проектом — .NET Framework 4.8.
При проверке трафика в Wireshark я считаю, что обнаружил проблему:
Запрос от программы .NET8 отправляет данные файла напрямую вместе с первым запросом

Код: Выделить всё

$X.$EJ@P8_8LPlPOST /api/upload_token HTTP/1.1
Host: 192.168.0.142
Accept: */*
Content-Type: multipart/form-data; boundary="afbc983b-2675-4133-b333-11fb5b878ca8"
Content-Length: 493

--afbc983b-2675-4133-b333-11fb5b878ca8
Content-Disposition: form-data; name="file"; filename="token_8961.bin"; filename*=utf-8''%22token_8961.bin%22
[FILE DATA]
--afbc983b-2675-4133-b333-11fb5b878ca8--
Пока программа .NET Framework 4.8 пытается разделить данные на 2 пакета:

Код: Выделить всё

$X.$EZ@ XPPVpCs\PPOST /api/upload_token HTTP/1.1
Accept: */*
Content-Type: multipart/form-data; boundary="4855026b-b3a3-42df-8abe-d56028e7c47f"
Host: 192.168.0.142
Content-Length: 493
Expect: 100-continue
Connection: Keep-Alive
и

Код: Выделить всё

$X.$EW@Psft=,Pw--2fc0624c-9294-44ef-949d-0988aca1b042
Content-Disposition: form-data; name="file"; filename="token_8961.bin"; filename*=utf-8''%22token_8961.bin%22
[FILE DATA]
--2fc0624c-9294-44ef-949d-0988aca1b042--
Но между двумя пакетами API уже отвечает 400:

Код: Выделить всё

$$X.E5WP=sftP
WHTTP/1.1 400 Bad Request
Connection: close
Content-Type: application/json

{"error":"Invalid filename. Expected TOKEN_8961.BIN"}
Я уже пробовал:
Установите для флага Expect100Continue значение false:

Код: Выделить всё

System.Net.ServicePointManager.Expect100Continue = false;
  • Удаляет заголовок Expect: 100-continue, но по-прежнему разделяет запрос
Удаляет заголовки Expect: 100-continue и Connection: Keep-Alive:

Код: Выделить всё

var request = new HttpRequestMessage(HttpMethod.Post, requestURL)
{
Content = payload
};
request.Headers.ConnectionClose = true;
request.Headers.ExpectContinue = false;
HttpClient.SendAsync(request);
  • Удаляет оба заголовка, но по-прежнему разделяет запрос.
Примечание: команда Curl для получения работающего запроса:

Код: Выделить всё

curl -X POST http://192.168.0.142/api/upload_token -F "file=@token_8961.bin;type=application/octet-stream"
Итак, мой вопрос: есть ли способ заставить .NET Framework4.8 HttpClient отправлять данные файла непосредственно в исходном запросе?

Подробнее здесь: https://stackoverflow.com/questions/798 ... ata-in-ini
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»