7

I am trying to upload a file with additional form data and post to Web API via MVC but i couldn't accomplish.

MVC Side

Firstly i got the submitted form at MVC. Here is the action for this.

    [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");
                }
            }

Below code post the Multipartform to Web 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);

As you can see i am trying to send file data and object with same MultipartFormDataContent. I couldn't find better way to send my entity as ObjectContent. Also i am using JSON.Net Serializer

Regarding to fiddler, post seems successfull.

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--

Web API Side

Finally i am catching post at Web API side and trying to parse but i couldn't. Because MultipartFormDataStreamProvider's FileData and FormData collections are allways empty.

[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);
            }              
        }

I hope you can help to find my mistake.

UPDATE

I also realized that, if i comment out StreamContent or ObjectContent and only add StringContent, still i can't get anything from MultipartFormDataStreamProvider.

1
  • I ran into a slightly different issue - the browser was dropping my files from the Request until I gave them a name/id. This helped a lot with diagnosing the issue though Commented Nov 2, 2015 at 18:47

1 Answer 1

5

Finally i resolved my problem and it was all about async :)

As you can see at API action method i had called ReadAsMultipartAsync method synchrously but this was a mistake. I had to call it with ContinueWith so after i changed my code like below my problem solved.

var files = Request.Content.ReadAsMultipartAsync(provider).ContinueWith<HttpResponseMessage>(task => {
                    if(task.IsFaulted)
                        throw task.Exception;
// do additional stuff
});
Sign up to request clarification or add additional context in comments.

5 Comments

Ah, I forgot that restriction.
I'm sorry, I'm a little confused here. What is the task exactly? and should I also hadle the form data in here too ?
I would like to see the entire working UpdateWithLogo body if thats possible
@TomasHesse i would like to help but I left that job and I have no longer access those code blocks

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.