C # StreamContent и File.OpenRead () не производят многокомпонентный HTTP-контент - PullRequest
0 голосов
/ 21 сентября 2018

У меня есть приложение .Net Core 2.0, которое отправляет файлы на конечную точку Web API с использованием многокомпонентного контента.Куда бы я ни посмотрел, например, C # HttpClient 4.5 multipart / form-data upload , создается впечатление, что это должно быть так же просто, как передать FileStream в StreamContent.Однако, когда я пишу сообщение, файл выглядит как текст, а не биты.

Фактический код:

var request = new HttpRequestMessage()
{
    Method = HttpMethod.Post,
    RequestUri = new Uri( "http://localhost:10442/filetest" )
};
var multiContent = new MultipartFormDataContent();

var filestream = File.OpenRead( path );
var filename = Path.GetFileName( path );
var streamContent = new StreamContent( filestream );
streamContent.Headers.Add( "Content-Type", "application/octet-stream" );
streamContent.Headers.Add( "Content-Disposition", $"form-data; name=\"file1\"; filename=\"{filename}\"" );

multiContent.Add( streamContent, "file", filename );
request.Content = multiContent;

var response = await new HttpClient().SendAsync( request );

Запрос выглядит так, что, как вы можете заметить,, не все в одной строке (что я считаю проблемой):

POST http://localhost:10442/filetest HTTP/1.1
Content-Type: multipart/form-data; boundary="c5295887-425d-4ec7-8638-20c6254f9e4b"
Content-Length: 88699
Host: localhost:10442

--c5295887-425d-4ec7-8638-20c6254f9e4b
Content-Type: application/octet-stream
Content-Disposition: form-data; name="file1"; filename="somepdf.pdf"

%PDF-1.7
%       
1 0 obj
<</Type/Catalog/Version/1.7/Pages 3 0 R/Outlines 2 0 R/Names 8 0 R/Metadata 31 0 R>>
endobj

Fiddler показывает весь пост вплоть до конечной границы, но await Request.Content.ReadAsStringAsync() в конечной точке показывает толькопервая пара дюжин байт (похоже, что поток не был завершен, но если Fiddler получил все это, разве моя конечная точка тоже не должна?)конечная точка;Я создал эту конечную точку для локального тестирования.

Исключение, которое я получаю: «Неожиданный конец многочастного потока MIME. Многочастное сообщение MIME не завершено».Для меня это имеет смысл как в том случае, если я действительно получаю только часть своего потока, так и в том случае, если разрывы строк сбрасывают что-то., это закрывает потоки, и я получаю исключения таким образом.

И для полноты, вот конечная точка, которую я называю:

public async void ReceiveFiles()
{
    // exception happens here:
    var mpData = await Request.Content.ReadAsMultipartAsync();
    await Task.FromResult( 0 );
}

Ответы [ 3 ]

0 голосов
/ 20 октября 2018

Я использую эту библиотеку: https://github.com/jgiacomini/Tiny.RestClient Для отправки многокомпонентных файлов проще отправлять многопользовательский файл.

Вот пример: await client.PostRequest ("MultiPart / Test").AsMultiPartFromDataRequest ().AddStream (stream1, "request", "request2.bin").AddStream (stream2, "request", "request2.bin") ExecuteAsync ();

0 голосов
/ 21 октября 2018

Попробуйте что-то вроде этого:

static int Main(string[] args)
{
    var request = new HttpRequestMessage()
    {
        Method = HttpMethod.Post,
        RequestUri = new Uri("http://localhost:10442/filetest")
    };
    var path = "c:\\temp\\foo.bak";

    using (var filestream = File.OpenRead(path))
    {
        var length = filestream.Length.ToString();
        var streamContent = new StreamContent(filestream);
        streamContent.Headers.Add("Content-Type", "application/octet-stream");
        streamContent.Headers.Add("Content-Length", length);


        request.Content = streamContent;

        Console.WriteLine($"Sending {length} bytes");
        var response = new HttpClient().SendAsync(request).Result;


        Console.WriteLine(response.Content.ReadAsStringAsync().Result);
    }

    Console.WriteLine("Hit any key to exit");
    Console.ReadKey();
    return 0;
}

и

    [HttpPost]
    public async Task<IActionResult> Upload()
    {
        var buf = new byte[1024 * 64];
        long totalBytes = 0;
        using (var rs = Request.Body)
        {
            while (1 == 1)
            {
                int bytesRead = await rs.ReadAsync(buf, 0, buf.Length);
                if (bytesRead == 0) break;
                totalBytes += bytesRead;
            }
        }
        var uploadedData = new
        {
            BytesRead = totalBytes
        };
        return new JsonResult(uploadedData) ;
    }
0 голосов
/ 18 октября 2018

Я пытаюсь решить подобную проблему, и я пока не на 100% к решению, но, возможно, некоторые из моих исследований могут вам помочь.

Мне было полезно прочитатьДокументы Microsoft для загрузки основных файлов .NET, особенно для больших файлов, которые используют потоки и данные многоэлементных форм: https://docs.microsoft.com/en-us/aspnet/core/mvc/models/file-uploads?view=aspnetcore-2.1#uploading-large-files-with-streaming

Вы уже ссылались на него, но в этом ответе есть некоторая полезная информация: C # HttpClient4.5 multipart / form-data upload

Это объясняет детали заголовка размещения содержимого и как он используется с запросами данных составной формы: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition#As_a_header_for_a_multipart_body

Что касается вашего конкретногопроблема в том, что файл отправляется в виде текста, а не битов, поскольку http основан на тексте, его можно отправлять только в виде текста, но этот текст можно закодировать по своему усмотрению.Возможно, для вашего StreamContent требуется определенная кодировка, например, кодировка base64 или аналогичная?Я действительно считаю, что переводы строки имеют большое значение в составном запросе, поэтому, надеюсь, будет достаточно установить кодировку для содержимого файла.

Другая возможность: может быть, вам потребуется установить дополнительную информацию в разделе файлаЗаголовки или в определении StreamContent, чтобы указать, что он должен ожидать продолжения, или что информация о границе не введена правильно?См. Составные формы из клиента C #

...