Custom form data with multiple files to Web API controller

asp.net-web-api, c#, multipartform-data

Solution

I used this along with angular and it worked fine for me:

public partial class UploadController : ApiController
{
    [HttpPost]
    public Task<HttpResponseMessage> PostFormData()
    {
        // Check if the request contains multipart/form-data.
        if (!Request.Content.IsMimeMultipartContent()) {
            throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
        }

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

        // Read the form data and return an async task.
        var task = Request.Content.ReadAsMultipartAsync(provider).
            ContinueWith<HttpResponseMessage>(t =>
            {
                if (t.IsFaulted || t.IsCanceled) {
                    Request.CreateErrorResponse(HttpStatusCode.InternalServerError, t.Exception);
                }


                foreach (MultipartFileData file in provider.FileData) {
                    using (StreamReader fileStream = new StreamReader(file.LocalFileName)){
                        if (provider.FormData.AllKeys.AsParallel().Contains("demo")){
                            //read demo key value from form data successfully
                        }
                        else{
                           //failed to read demo key value from form.
                        }
                    }
                }
                return Request.CreateResponse(HttpStatusCode.OK, "OK");
            });

        return task;
    }
...

Problem

I have problems of getting all the form data I've specified in my API Controller. javascript upload function: ``` $scope.upload[index] = $upload.upload({ url: '/api/upload/', method: 'POST', data: { Photographer: $scope.models[index].photographer, Description: $scope.models[index].desc }, file: $scope.models[index].file }) ``` Form data: Works as I want it to, for each request that is sent it includes my values as i want it to. ``` ------WebKitFormBoundaryzlLjAnm449nw1EvC Content-Disposition: form-data; name="Photographer" Scott Johnson ------WebKitFormBoundaryzlLjAnm449nw1EvC Content-Disposition: form-data; name="Description" Image taken with a Nikon camerea ------WebKitFormBoundaryzlLjAnm449nw1EvC Content-Disposition: form-data; name="file"; filename="moxnes.jpg" Content-Type: image/jpeg ``` My Web API Controller: Template from this guide ``` public class UploadController : ApiController { public async Task < HttpResponseMessage > PostFormData() { var root = HttpContext.Current.Server.MapPath("~/App_Data"); var provider = new MultipartFormDataStreamProvider(root); try { // Read the form data. await Request.Content.ReadAsMultipartAsync(provider); // Show all the key-value pairs. foreach(var key in provider.FormData.AllKeys) { foreach(var val in provider.FormData.GetValues(key)) { var keyValue = string.Format("{0}: {1}", key, val); } } foreach(MultipartFileData fileData in provider.FileData) { var fileName = fileData.Headers.ContentDisposition.FileName; } return Request.CreateResponse(HttpStatusCode.OK); } catch (Exception e) { return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e); } } } ``` Here's the problem: The controller can receive multiple request asynchronously and read all the files through this loop: `foreach(MultipartFileData fileData in provider.FileData)` which works fine, but my other form data values (Phtographer and Description) does only include values from one of the requests (the last request received). ``` foreach(var key in provider.FormData.AllKeys) ``` I need to take out each requests form data values. How can I do it, or is there any better way of solving this? Maybe by adding a model as parameter?

Original source