Загрузка файла с дополнительными данными формы в веб-API из MVC

Я пытаюсь загрузить файл с дополнительными данными формы и отправить его в веб-API через MVC, но мне это не удалось.

Сторона MVC

Сначала я получил отправленную форму в MVC. Вот действие для этого.

    [HttpPost]
            public async Task<ActionResult> Edit(BrandInfo entity) {

                try {
                    byte[] logoData = null;
                    if(Request.Files.Count > 0) {
                        HttpPostedFileBase logo = Request.Files[0];
                        logoData = new byte[logo.ContentLength];
                        logo.InputStream.Read(logoData, 0, logo.ContentLength);
                        entity.Logo = logo.FileName;
                        entity = await _repo.Update(entity.BrandID, entity, logoData);
                    }
                    else
                        entity = await _repo.Update(entity,entity.BrandID);
                    return RedirectToAction("Index", "Brand");
                }
                catch(HttpApiRequestException e) {
// logging, etc                   
                    return RedirectToAction("Index", "Brand");
                }
            }

Ниже код опубликуйте Multipartform для веб-API

string requestUri = UriUtil.BuildRequestUri(_baseUri, uriTemplate, uriParameters: uriParameters);
            MultipartFormDataContent formData = new MultipartFormDataContent();
            StreamContent streamContent = null;
            streamContent = new StreamContent(new MemoryStream(byteData));            
            streamContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") {
                FileName = "\"" + fileName + "\"",
                Name = "\"filename\""
            };
            streamContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
            formData.Add(streamContent);
            formData.Add(new ObjectContent<TRequestModel>(requestModel, _writerMediaTypeFormatter), "entity");
            return _httpClient.PutAsync(requestUri, formData).GetHttpApiResponseAsync<TResult>(_formatters);

Как видите, я пытаюсь отправить данные файла и объект с одним и тем же MultipartFormDataContent. Я не мог найти лучшего способа отправить свою сущность как ObjectContent. Также я использую JSON.Net Serializer

Что касается скрипача, пост кажется успешным.

PUT http://localhost:12836/api/brand/updatewithlogo/13 HTTP/1.1
Content-Type: multipart/form-data; boundary="10255239-d2a3-449d-8fad-2f31b1d00d2a"
Host: localhost:12836
Content-Length: 4341
Expect: 100-continue

--10255239-d2a3-449d-8fad-2f31b1d00d2a
Content-Disposition: form-data; filename="web-host-logo.gif"; name="filename"
Content-Type: application/octet-stream

GIF89a��L������X�������wW����������xH�U�)�-�k6�������v6�������̥�v�J���������7����V:�=#�ի�I(�xf�$�������
// byte data
// byte data
'pf�Y��y�ؙ�ڹ�(�;
--10255239-d2a3-449d-8fad-2f31b1d00d2a
Content-Type: application/json; charset=utf-8
Content-Disposition: form-data; name=entity

{"BrandID":13,"AssetType":null,"AssetTypeID":2,"Logo":"web-host-logo.gif","Name":"Geçici Brand","Models":null,"SupplierBrands":null}
--10255239-d2a3-449d-8fad-2f31b1d00d2a--

На стороне веб-API

Наконец, я ловлю сообщение на стороне веб-API и пытаюсь проанализировать, но не смог. Потому что коллекции FileData и FormData MultipartFormDataStreamProvider всегда пусты.

[HttpPut]
        public void UpdateWithLogo(int id) {
            if(Request.Content.IsMimeMultipartContent()) {
                var x = 1; // this code has no sense, only here to check IsMimeMultipartContent
            }  

            string root = HttpContext.Current.Server.MapPath("~/App_Data");
            var provider = new MultipartFormDataStreamProvider(root);

            try {
                // Read the form data.
                 Request.Content.ReadAsMultipartAsync(provider);

                 foreach(var key in provider.FormData.AllKeys) {
                     foreach(var val in provider.FormData.GetValues(key)) {
                         _logger.Info(string.Format("{0}: {1}", key, val));
                     }
                 }

                // This illustrates how to get the file names.
                foreach(MultipartFileData file in provider.FileData) {
                    _logger.Info(file.Headers.ContentDisposition.FileName);
                    _logger.Info("Server file path: " + file.LocalFileName);
                }               
            }
            catch(Exception e) {
                throw new HttpApiRequestException("Error", HttpStatusCode.InternalServerError, null);
            }              
        }

Надеюсь, вы поможете найти мою ошибку.

ОБНОВЛЕНИЕ

Я также понял, что если я закомментирую StreamContent или ObjectContent и добавлю только StringContent, я все равно ничего не смогу получить из MultipartFormDataStreamProvider.


person bahadir arslan    schedule 26.03.2013    source источник
comment
Я столкнулся с немного другой проблемой - браузер удалял мои файлы из запроса, пока я не дал им имя/идентификатор. Это очень помогло с диагностикой проблемы, хотя   -  person brichins    schedule 02.11.2015


Ответы (1)


Наконец-то я решил свою проблему, и все дело было в асинхронности :)

Как вы можете видеть в методе действия API, я синхронно вызвал метод ReadAsMultipartAsync, но это была ошибка. Мне пришлось вызвать его с помощью ContinueWith, поэтому после того, как я изменил свой код, как показано ниже, моя проблема была решена.

var files = Request.Content.ReadAsMultipartAsync(provider).ContinueWith<HttpResponseMessage>(task => {
                    if(task.IsFaulted)
                        throw task.Exception;
// do additional stuff
});
person bahadir arslan    schedule 26.03.2013
comment
Ах, я забыл это ограничение. - person anaximander; 26.03.2013
comment
Извините, я немного запутался здесь. Какая именно задача? и должен ли я также иметь данные формы здесь? - person Bobby5193; 28.09.2013
comment
Может ты попал в это? stackoverflow.com/questions/15201255/ - person granadaCoder; 26.01.2016
comment
Я хотел бы увидеть все рабочее тело UpdateWithLogo, если это возможно. - person Tomas Hesse; 26.07.2017
comment
@TomasHesse, я хотел бы помочь, но я ушел с этой работы, и у меня больше нет доступа к этим блокам кода. - person bahadir arslan; 29.07.2017