Использование MultipartContent - это работает, но работает ли оно правильно? - PullRequest
0 голосов
/ 30 апреля 2020

У меня есть небольшое приложение, которое генерирует HttpMessage с многокомпонентным контентом ...

using (var client = new HttpClient())
{
    using (var content = new MultipartContent("mixed", "----123"))
    {
        content.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/mixed; boundary=----123");
        // repeated calls to content.Add(...)

        var result = client.PostAsync(url, content). Result;

        Console.WriteLine(result);
    }
}

, и у меня есть маленький HttpServer, который прослушивает вызовы POST и делает это, когда он получает один ...

var streamContent = new StreamContent(inputStream);
streamContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/mixed; boundary=----123");
var provider = streamContent.ReadAsMultipartAsync().Result;

foreach (var httpContent in provider.Contents)
{
    var t = httpContent.Headers.ContentType;
    var c = httpContent.ReadAsStringAsync().Result;
}

И все это работает.

Но если в моем коде приемника я не включаю строку streamContent.Headers.ContentType..., то приемник падает на var provider... строка с ошибкой Invalid 'HttpContent' instance provided. It does not have a content-type header value. 'HttpContent' instances must have a content-type header starting with 'multipart/'..

Итак, хотя у меня есть код, который работает, он будет работать, только если я заранее знаю, какой будет граница.

Это не может быть правдой.

Я просмотрел и попробовал десятки перестановок на основе вопросов здесь, в SO и в других местах, но я не могу найти ничего, что работает без меня установка заголовка ContentType в приемнике и, следовательно, знание значения границы.

Что должен делать?

ОБНОВЛЕНИЕ

Если я удаляю граничную часть заголовка ContentType в приемнике, он все равно падает, но с другой ошибкой ... Invalid 'HttpContent' instance provided. It does not have a 'multipart' content-type header with a 'boundary' parameter.

1 Ответ

1 голос
/ 30 апреля 2020

Я не думаю, что ваш сервер делает то, что вы думаете, он делает. new StreamContent(Stream) используется, когда вы создаете свой собственный потоковый контент с намерением вернуть его из действия контроллера. И поток, который вы передаете ему, должен содержать необработанные данные (сущность, тело ответа), которые будут возвращены. Он не пытается интерпретировать данные из потока в любом случае. Даже если вы передадите действительный поток http в параметре, он не будет пытаться отделить заголовки типа содержимого от него - вы должны предоставить его. И это большой ЕСЛИ, вы не показали, где вы получаете inputStream, это не стандартная часть MVC.

Фактический контент, который вы получили от клиента, доступен в Request.Content вместе с правильные заголовки, такие как тип содержимого или границы. ReadAsMultipartAsyn c также должен работать над этим, но я никогда не пробовал это расширение на практике.

В качестве примечания, использование Task.Result должно быть последним средством. Сделайте ваш контроллер асинхронным c и дождитесь этой задачи.

Редактировать: для иллюстрации я думаю, что это сработает и не требует знания границы заранее. Тем не менее, это очень неоптимальное решение, когда вы можете просто позвонить Request.Content.ReadAsMultipartAsync():

var streamContent = new StreamContent(inputStream);
streamContent.Headers.ContentType = Request.Content.Headers.ContentType;
                                 // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
var provider = streamContent.ReadAsMultipartAsync().Result;

foreach (var httpContent in provider.Contents)
{
    var t = httpContent.Headers.ContentType;
    var c = httpContent.ReadAsStringAsync().Result;
}
...